1: // Copyright (C) 1984-1998 by Symantec
2: // Copyright (C) 2000-2011 by Digital Mars
3: // All Rights Reserved
4: // http://www.digitalmars.com
5: // Written by Walter Bright
6: /*
7: * This source file is made available for personal use
8: * only. The license is in /dmd/src/dmd/backendlicense.txt
9: * or /dm/src/dmd/backendlicense.txt
10: * For any other uses, please contact Digital Mars.
11: */
12:
13: #if !SPP
14:
15: #include <stdio.h>
16: #include <string.h>
17: #include <stdlib.h>
18: #include <time.h>
19:
20: #if __sun&&__SVR4
21: #include <alloca.h>
22: #elif _MSC_VER
23: #include <malloc.h>
24: #endif
25:
26: #include "cc.h"
27: #include "el.h"
28: #include "oper.h"
29: #include "code.h"
30: #include "global.h"
31: #include "type.h"
32:
33: static char __file__[] = __FILE__; /* for tassert.h */
34: #include "tassert.h"
35:
36: /* Generate the appropriate ESC instruction */
37: #define ESC(MF,b) (0xD8 + ((MF) << 1) + (b))
38: enum MF
39: { // Values for MF
40: MFfloat = 0,
41: MFlong = 1,
42: MFdouble = 2,
43: MFword = 3
44: };
45: code * genf2(code *c,unsigned op,unsigned rm);
46:
47: targ_size_t paramsize(elem *e,unsigned stackalign);
48: STATIC code * funccall (elem *,unsigned,unsigned,regm_t *,regm_t);
49:
50: /* array to convert from index register to r/m field */
51: /* AX CX DX BX SP BP SI DI */
52: static const signed char regtorm32[8] = { 0, 1, 2, 3,-1, 5, 6, 7 };
53: signed char regtorm [8] = { -1,-1,-1, 7,-1, 6, 4, 5 };
54:
55: /**************************
56: * Determine if e is a 32 bit scaled index addressing mode.
57: * Returns:
58: * 0 not a scaled index addressing mode
59: * !=0 the value for ss in the SIB byte
60: */
61:
62: int isscaledindex(elem *e)
63: { targ_uns ss;
64:
65: assert(!I16);
66: while (e->Eoper == OPcomma)
67: e = e->E2;
68: if (!(e->Eoper == OPshl && !e->Ecount &&
69: e->E2->Eoper == OPconst &&
70: (ss = e->E2->EV.Vuns) <= 3
71: )
72: )
73: ss = 0;
74: return ss;
75: }
76:
77: /*********************************************
78: * Generate code for which isscaledindex(e) returned a non-zero result.
79: */
80:
81: code *cdisscaledindex(elem *e,regm_t *pidxregs,regm_t keepmsk)
82: { code *c;
83: regm_t r;
84:
85: // Load index register with result of e->E1
86: c = NULL;
87: while (e->Eoper == OPcomma)
88: {
89: r = 0;
90: c = cat(c,scodelem(e->E1,&r,keepmsk,TRUE));
91: freenode(e);
92: e = e->E2;
93: }
94: assert(e->Eoper == OPshl);
95: c = cat(c,scodelem(e->E1,pidxregs,keepmsk,TRUE));
96: freenode(e->E2);
97: freenode(e);
98: return c;
99: }
100:
101: /***********************************
102: * Determine index if we can do two LEA instructions as a multiply.
103: * Returns:
104: * 0 can't do it
105: */
106:
107: static struct Ssindex
108: {
109: targ_uns product;
110: char ss1;
111: char ss2;
112: char ssflags;
113: #define SSFLnobp 1 // can't have EBP in relconst
114: #define SSFLnobase1 2 // no base register for first LEA
115: #define SSFLnobase 4 // no base register
116: #define SSFLlea 8 // can do it in one LEA
117: } ssindex_array[] =
118: { {0, 0,0}, // [0] is a place holder
119:
120: {3, 1,0,SSFLnobp | SSFLlea},
121: {5, 2,0,SSFLnobp | SSFLlea},
122: {9, 3,0,SSFLnobp | SSFLlea},
123:
124: {6, 1,1,SSFLnobase},
125: {12,1,2,SSFLnobase},
126: {24,1,3,SSFLnobase},
127: {10,2,1,SSFLnobase},
128: {20,2,2,SSFLnobase},
129: {40,2,3,SSFLnobase},
130: {18,3,1,SSFLnobase},
131: {36,3,2,SSFLnobase},
132: {72,3,3,SSFLnobase},
133:
134: {15,2,1,SSFLnobp},
135: {25,2,2,SSFLnobp},
136: {27,3,1,SSFLnobp},
137: {45,3,2,SSFLnobp},
138: {81,3,3,SSFLnobp},
139:
140: {16,3,1,SSFLnobase1 | SSFLnobase},
141: {32,3,2,SSFLnobase1 | SSFLnobase},
142: {64,3,3,SSFLnobase1 | SSFLnobase},
143: };
144:
145: int ssindex(int op,targ_uns product)
146: { int i;
147:
148: if (op == OPshl)
149: product = 1 << product;
150: for (i = 1; i < arraysize(ssindex_array); i++)
151: {
152: if (ssindex_array[i].product == product)
153: return i;
154: }
155: return 0;
156: }
157:
158: /***************************************
159: * Build an EA of the form disp[base][index*scale].
160: * Input:
161: * c struct to fill in
162: * base base register (-1 if none)
163: * index index register (-1 if none)
164: * scale scale factor - 1,2,4,8
165: * disp displacement
166: */
167:
168: void buildEA(code *c,int base,int index,int scale,targ_size_t disp)
169: { unsigned char rm;
170: unsigned char sib;
171: unsigned char rex = 0;
172:
173: sib = 0;
174: if (!I16)
175: { unsigned ss;
176:
177: assert(index != SP);
178:
179: switch (scale)
180: { case 1: ss = 0; break;
181: case 2: ss = 1; break;
182: case 4: ss = 2; break;
183: case 8: ss = 3; break;
184: default: assert(0);
185: }
186:
187: if (base == -1)
188: {
189: if (index == -1)
190: rm = modregrm(0,0,5);
191: else
192: {
193: rm = modregrm(0,0,4);
194: sib = modregrm(ss,index & 7,5);
195: if (index & 8)
196: rex |= REX_X;
197: }
198: }
199: else if (index == -1)
200: {
201: if (base == SP)
202: {
203: rm = modregrm(2,0,4);
204: sib = modregrm(0,4,SP);
205: }
206: else
207: { rm = modregrm(2,0,base & 7);
208: if (base & 8)
209: { rex |= REX_B;
210: if (base == R12)
211: {
212: rm = modregrm(2,0,4);
213: sib = modregrm(0,4,4);
214: }
215: }
216: }
217: }
218: else
219: {
220: rm = modregrm(2,0,4);
221: sib = modregrm(ss,index & 7,base & 7);
222: if (index & 8)
223: rex |= REX_X;
224: if (base & 8)
225: rex |= REX_B;
226: }
227: }
228: else
229: {
230: // -1 AX CX DX BX SP BP SI DI
231: static unsigned char EA16rm[9][9] =
232: {
233: { 0x06,0x09,0x09,0x09,0x87,0x09,0x86,0x84,0x85, }, // -1
234: { 0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09, }, // AX
235: { 0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09, }, // CX
236: { 0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09, }, // DX
237: { 0x87,0x09,0x09,0x09,0x09,0x09,0x09,0x80,0x81, }, // BX
238: { 0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09, }, // SP
239: { 0x86,0x09,0x09,0x09,0x09,0x09,0x09,0x82,0x83, }, // BP
240: { 0x84,0x09,0x09,0x09,0x80,0x09,0x82,0x09,0x09, }, // SI
241: { 0x85,0x09,0x09,0x09,0x81,0x09,0x83,0x09,0x09, } // DI
242: };
243:
244: assert(scale == 1);
245: rm = EA16rm[base + 1][index + 1];
246: assert(rm != 9);
247: }
248: c->Irm = rm;
249: c->Isib = sib;
250: c->Irex = rex;
251: c->IFL1 = FLconst;
252: c->IEV1.Vuns = disp;
253: }
254:
255: /*********************************************
256: * Build REX, modregrm and sib bytes
257: */
258:
259: unsigned buildModregrm(int mod, int reg, int rm)
260: { unsigned m;
261: if (I16)
262: m = modregrm(mod, reg, rm);
263: else
264: {
265: if ((rm & 7) == SP && mod != 3)
266: m = (modregrm(0,4,SP) << 8) | modregrm(mod,reg & 7,4);
267: else
268: m = modregrm(mod,reg & 7,rm & 7);
269: if (reg & 8)
270: m |= REX_R << 16;
271: if (rm & 8)
272: m |= REX_B << 16;
273: }
274: return m;
275: }
276:
277: /**************************
278: * For elems in regcon that don't match regconsave,
279: * clear the corresponding bit in regcon.cse.mval.
280: * Do same for regcon.immed.
281: */
282:
283: void andregcon(con_t *pregconsave)
284: {
285: regm_t m = ~1;
286: for (int i = 0; i < REGMAX; i++)
287: { if (pregconsave->cse.value[i] != regcon.cse.value[i])
288: regcon.cse.mval &= m;
289: if (pregconsave->immed.value[i] != regcon.immed.value[i])
290: regcon.immed.mval &= m;
291: m <<= 1;
292: m |= 1;
293: }
294: //printf("regcon.cse.mval = x%x, regconsave->mval = x%x ",regcon.cse.mval,pregconsave->cse.mval);
295: regcon.used |= pregconsave->used;
296: regcon.cse.mval &= pregconsave->cse.mval;
297: regcon.immed.mval &= pregconsave->immed.mval;
298: regcon.params &= pregconsave->params;
299: //printf("regcon.cse.mval®con.cse.mops = x%x, regcon.cse.mops = x%x\n",regcon.cse.mval & regcon.cse.mops,regcon.cse.mops);
300: regcon.cse.mops &= regcon.cse.mval;
301: }
302:
303: /*********************************
304: * Scan down comma-expressions.
305: * Output:
306: * *pe = first elem down right side that is not an OPcomma
307: * Returns:
308: * code generated for left branches of comma-expressions
309: */
310:
311: code *docommas(elem **pe)
312: { elem *e;
313: code *cc;
314: unsigned stackpushsave;
315: int stackcleansave;
316:
317: stackpushsave = stackpush;
318: stackcleansave = cgstate.stackclean;
319: cgstate.stackclean = 0;
320: cc = CNIL;
321: e = *pe;
322: while (1)
323: { elem *eold;
324: regm_t retregs;
325:
326: if (configv.addlinenumbers && e->Esrcpos.Slinnum)
327: { cc = genlinnum(cc,e->Esrcpos);
328: //e->Esrcpos.Slinnum = 0; // don't do it twice
329: }
330: if (e->Eoper != OPcomma)
331: break;
332: retregs = 0;
333: cc = cat(cc,codelem(e->E1,&retregs,TRUE));
334: eold = e;
335: e = e->E2;
336: freenode(eold);
337: }
338: *pe = e;
339: assert(cgstate.stackclean == 0);
340: cgstate.stackclean = stackcleansave;
341: cc = genstackclean(cc,stackpush - stackpushsave,0);
342: return cc;
343: }
344:
345: /****************************************
346: * Clean stack after call to codelem().
347: */
348:
349: code *gencodelem(code *c,elem *e,regm_t *pretregs,bool constflag)
350: {
351: if (e)
352: {
353: unsigned stackpushsave;
354: int stackcleansave;
355:
356: stackpushsave = stackpush;
357: stackcleansave = cgstate.stackclean;
358: cgstate.stackclean = 0; // defer cleaning of stack
359: c = cat(c,codelem(e,pretregs,constflag));
360: assert(cgstate.stackclean == 0);
361: cgstate.stackclean = stackcleansave;
362: c = genstackclean(c,stackpush - stackpushsave,*pretregs); // do defered cleaning
363: }
364: return c;
365: }
366:
367: /********************************************
368: * Gen a save/restore sequence for mask of registers.
369: */
370:
371: void gensaverestore2(regm_t regm,code **csave,code **crestore)
372: {
373: code *cs1 = *csave;
374: code *cs2 = *crestore;
375:
376: //printf("gensaverestore2(%s)\n", regm_str(regm));
377: regm &= mBP | mES | ALLREGS | XMMREGS;
378: for (int i = 0; regm; i++)
379: {
380: if (regm & 1)
381: {
382: if (i == ES)
383: {
384: cs1 = gen1(cs1, 0x06); // PUSH ES
385: cs2 = cat(gen1(CNIL, 0x07),cs2); // POP ES
386: }
387: else if (i >= XMM0)
388: { unsigned idx;
389: cs1 = regsave.save(cs1, i, &idx);
390: cs2 = regsave.restore(cs2, i, idx);
391: }
392: else
393: {
394: cs1 = gen1(cs1,0x50 + (i & 7)); // PUSH i
395: code *c = gen1(NULL, 0x58 + (i & 7)); // POP i
396: if (i & 8)
397: { code_orrex(cs1, REX_B);
398: code_orrex(c, REX_B);
399: }
400: cs2 = cat(c,cs2);
401: }
402: }
403: regm >>= 1;
404: }
405: *csave = cs1;
406: *crestore = cs2;
407: }
408:
409: void gensaverestore(regm_t regm,code **csave,code **crestore)
410: {
411: *csave = NULL;
412: *crestore = NULL;
413: gensaverestore2(regm, csave, crestore);
414: }
415:
416: /****************************************
417: * Clean parameters off stack.
418: * Input:
419: * numpara amount to adjust stack pointer
420: * keepmsk mask of registers to not destroy
421: */
422:
423: code *genstackclean(code *c,unsigned numpara,regm_t keepmsk)
424: {
425: //dbg_printf("genstackclean(numpara = %d, stackclean = %d)\n",numpara,cgstate.stackclean);
426: if (numpara && (cgstate.stackclean || STACKALIGN == 16))
427: {
428: #if 0 // won't work if operand of scodelem
429: if (numpara == stackpush && // if this is all those pushed
430: needframe && // and there will be a BP
431: !config.windows &&
432: !(regcon.mvar & fregsaved) // and no registers will be pushed
433: )
434: c = genregs(c,0x89,BP,SP); // MOV SP,BP
435: else
436: #endif
437: { regm_t scratchm = 0;
438:
439: if (numpara == REGSIZE && config.flags4 & CFG4space)
440: {
441: scratchm = ALLREGS & ~keepmsk & regcon.used & ~regcon.mvar;
442: }
443:
444: if (scratchm)
445: { unsigned r;
446: c = cat(c,allocreg(&scratchm,&r,TYint));
447: c = gen1(c,0x58 + r); // POP r
448: }
449: else
450: { c = genc2(c,0x81,modregrm(3,0,SP),numpara); // ADD SP,numpara
451: if (I64)
452: code_orrex(c, REX_W);
453: }
454: }
455: stackpush -= numpara;
456: c = genadjesp(c,-numpara);
warning C4146: unary minus operator applied to unsigned type, result still unsigned
457: }
458: return c;
459: }
460:
461:
462: /*********************************
463: * Generate code for a logical expression.
464: * Input:
465: * e elem
466: * jcond
467: * bit 1 if TRUE then goto jump address if e
468: * if FALSE then goto jump address if !e
469: * 2 don't call save87()
470: * fltarg FLcode or FLblock, flavor of target if e evaluates to jcond
471: * targ either code or block pointer to destination
472: */
473:
474: code *logexp(elem *e,int jcond,unsigned fltarg,code *targ)
475: { code *c,*ce,*cnop;
476: regm_t retregs;
477: unsigned op;
478:
479: //printf("logexp(e = %p, jcond = %d)\n", e, jcond);
480: int no87 = (jcond & 2) == 0;
481: _chkstack();
482: code *cc = docommas(&e); // scan down commas
483: cgstate.stackclean++;
484:
485: if (EOP(e) && !e->Ecount) /* if operator and not common sub */
486: { con_t regconsave;
487:
488: switch (e->Eoper)
489: { case OPoror:
490: if (jcond & 1)
491: { c = logexp(e->E1,jcond,fltarg,targ);
492: regconsave = regcon;
493: ce = logexp(e->E2,jcond,fltarg,targ);
494: }
495: else
496: { cnop = gennop(CNIL);
497: c = logexp(e->E1,jcond | 1,FLcode,cnop);
498: regconsave = regcon;
499: ce = logexp(e->E2,jcond,fltarg,targ);
500: ce = cat(ce,cnop);
501: }
502: cnop = CNIL;
503: goto L1;
504:
505: case OPandand:
506: if (jcond & 1)
507: { cnop = gennop(CNIL); /* a dummy target address */
508: c = logexp(e->E1,jcond & ~1,FLcode,cnop);
509: regconsave = regcon;
510: ce = logexp(e->E2,jcond,fltarg,targ);
511: }
512: else
513: { c = logexp(e->E1,jcond,fltarg,targ);
514: regconsave = regcon;
515: ce = logexp(e->E2,jcond,fltarg,targ);
516: cnop = CNIL;
517: }
518: L1: andregcon(®consave);
519: freenode(e);
520: c = cat4(cc,c,ce,cnop);
521: goto Lret;
522:
523: case OPnot:
524: jcond ^= 1;
525: case OPbool:
526: case OPs8int:
527: case OPu8int:
528: case OPs16_32:
529: case OPu16_32:
530: case OPs32_64:
531: case OPu32_64:
532: case OPu32_d:
533: case OPd_ld:
534: c = logexp(e->E1,jcond,fltarg,targ);
535: freenode(e);
536: goto Lretc;
537:
538: case OPcond:
539: {
540: code *cnop2 = gennop(CNIL); // addresses of start of leaves
541: cnop = gennop(CNIL);
542: c = logexp(e->E1,FALSE,FLcode,cnop2); /* eval condition */
543: con_t regconold = regcon;
544: ce = logexp(e->E2->E1,jcond,fltarg,targ);
545: ce = genjmp(ce,JMP,FLcode,(block *) cnop); /* skip second leaf */
546:
547: regconsave = regcon;
548: regcon = regconold;
549:
550: code_next(cnop2) = logexp(e->E2->E2,jcond,fltarg,targ);
551: andregcon(®conold);
552: andregcon(®consave);
553: freenode(e->E2);
554: freenode(e);
555: c = cat6(cc,c,NULL,ce,cnop2,cnop);
556: goto Lret;
557: }
558: }
559: }
560:
561: /* Special code for signed long compare.
562: * Not necessary for I64 until we do cents.
563: */
564: if (OTrel2(e->Eoper) && /* if < <= >= > */
565: !e->Ecount &&
566: ( (I16 && tybasic(e->E1->Ety) == TYlong && tybasic(e->E2->Ety) == TYlong) ||
567: (I32 && tybasic(e->E1->Ety) == TYllong && tybasic(e->E2->Ety) == TYllong))
568: )
569: {
570: c = longcmp(e,jcond,fltarg,targ);
warning C4800: 'int' : forcing value to bool 'true' or 'false' (performance warning)
571: goto Lretc;
572: }
573:
574: retregs = mPSW; /* return result in flags */
575: op = jmpopcode(e); /* get jump opcode */
576: if (!(jcond & 1))
577: op ^= 0x101; // toggle jump condition(s)
578: c = codelem(e,&retregs,TRUE); /* evaluate elem */
579: if (no87)
580: c = cat(c,cse_flush(no87)); // flush CSE's to memory
581: genjmp(c,op,fltarg,(block *) targ); /* generate jmp instruction */
582: Lretc:
583: c = cat(cc,c);
584: Lret:
585: cgstate.stackclean--;
586: return c;
587: }
588:
589:
590: /******************************
591: * Routine to aid in setting things up for gen().
592: * Look for common subexpression.
593: * Can handle indirection operators, but not if they're common subs.
594: * Input:
595: * e -> elem where we get some of the data from
596: * cs -> partially filled code to add
597: * op = opcode
598: * reg = reg field of (mod reg r/m)
599: * offset = data to be added to Voffset field
600: * keepmsk = mask of registers we must not destroy
601: * desmsk = mask of registers destroyed by executing the instruction
602: * Returns:
603: * pointer to code generated
604: */
605:
606: code *loadea(elem *e,code *cs,unsigned op,unsigned reg,targ_size_t offset,
607: regm_t keepmsk,regm_t desmsk)
608: {
609: code *c,*cg,*cd;
610:
611: #ifdef DEBUG
612: if (debugw)
613: printf("loadea: e=%p cs=%p op=x%x reg=%d offset=%lld keepmsk=x%x desmsk=x%x\n",
614: e,cs,op,reg,(unsigned long long)offset,keepmsk,desmsk);
615: #endif
616:
617: assert(e);
618: cs->Iflags = 0;
619: cs->Irex = 0;
620: cs->Iop = op;
621: tym_t tym = e->Ety;
622: int sz = tysize(tym);
623:
624: /* Determine if location we want to get is in a register. If so, */
625: /* substitute the register for the EA. */
626: /* Note that operators don't go through this. CSE'd operators are */
627: /* picked up by comsub(). */
628: if (e->Ecount && /* if cse */
629: e->Ecount != e->Ecomsub && /* and cse was generated */
630: op != 0x8D && op != 0xC4 && /* and not an LEA or LES */
631: (op != 0xFF || reg != 3) && /* and not CALLF MEM16 */
632: (op & 0xFFF8) != 0xD8) // and not 8087 opcode
633: {
634: assert(!EOP(e)); /* can't handle this */
635: regm_t rm = regcon.cse.mval & ~regcon.cse.mops & ~regcon.mvar; // possible regs
636: if (sz > REGSIZE) // value is in 2 or 4 registers
637: {
638: if (I16 && sz == 8) // value is in 4 registers
639: { static regm_t rmask[4] = { mDX,mCX,mBX,mAX };
640: rm &= rmask[offset >> 1];
641: }
642:
643: else if (offset)
644: rm &= mMSW; /* only high words */
645: else
646: rm &= mLSW; /* only low words */
647: }
648: for (unsigned i = 0; rm; i++)
649: { if (mask[i] & rm)
650: { if (regcon.cse.value[i] == e && // if register has elem
651: /* watch out for a CWD destroying DX */
652: !(i == DX && op == 0xF7 && desmsk & mDX))
653: {
654: /* if ES, then it can only be a load */
655: if (i == ES)
656: { if (op != 0x8B)
657: goto L1; /* not a load */
658: cs->Iop = 0x8C; /* MOV reg,ES */
659: cs->Irm = modregrm(3,0,reg & 7);
660: if (reg & 8)
661: code_orrex(cs, REX_B);
662: }
663: else // XXX reg,i
664: {
665: cs->Irm = modregrm(3,reg & 7,i & 7);
666: if (reg & 8)
667: cs->Irex |= REX_R;
668: if (i & 8)
669: cs->Irex |= REX_B;
670: if (sz == 1 && I64 && (i >= 4 || reg >= 4))
671: cs->Irex |= REX;
672: if (I64 && (sz == 8 || sz == 16))
673: cs->Irex |= REX_W;
674: }
675: c = CNIL;
676: goto L2;
677: }
678: rm &= ~mask[i];
679: }
680: }
681: }
682:
683: L1:
684: c = getlvalue(cs,e,keepmsk);
685: if (offset == REGSIZE)
686: getlvalue_msw(cs);
687: else
688: cs->IEVoffset1 += offset;
689: if (I64)
690: { if (reg >= 4 && sz == 1) // if byte register
691: // Can only address those 8 bit registers if a REX byte is present
692: cs->Irex |= REX;
693: if ((op & 0xFFFFFFF8) == 0xD8)
694: cs->Irex &= ~REX_W; // not needed for x87 ops
695: }
696: code_newreg(cs, reg); // OR in reg field
697: if (!I16)
698: {
699: if (reg == 6 && op == 0xFF || /* don't PUSH a word */
700: op == 0x0FB7 || op == 0x0FBF || /* MOVZX/MOVSX */
701: (op & 0xFFF8) == 0xD8 || /* 8087 instructions */
702: op == 0x8D) /* LEA */
703: {
704: cs->Iflags &= ~CFopsize;
705: if (reg == 6 && op == 0xFF) // if PUSH
706: cs->Irex &= ~REX_W; // REX is ignored for PUSH anyway
707: }
708: }
709: else if ((op & 0xFFF8) == 0xD8 && ADDFWAIT())
710: cs->Iflags |= CFwait;
711: L2:
712: cg = getregs(desmsk); /* save any regs we destroy */
713:
714: /* KLUDGE! fix up DX for divide instructions */
715: cd = CNIL;
716: if (op == 0xF7 && desmsk == (mAX|mDX)) /* if we need to fix DX */
717: { if (reg == 7) /* if IDIV */
718: { cd = gen1(cd,0x99); // CWD
719: if (I64 && sz == 8)
720: code_orrex(cd, REX_W);
721: }
722: else if (reg == 6) // if DIV
723: { cd = genregs(cd,0x33,DX,DX); // XOR DX,DX
724: if (I64 && sz == 8)
725: code_orrex(cd, REX_W);
726: }
727: }
728:
729: // Eliminate MOV reg,reg
730: if ((cs->Iop & ~3) == 0x88 &&
731: (cs->Irm & 0xC7) == modregrm(3,0,reg & 7))
732: {
733: unsigned r = cs->Irm & 7;
734: if (cs->Irex & REX_B)
735: r |= 8;
736: if (r == reg)
737: cs->Iop = NOP;
738: }
739:
740: return cat4(c,cg,cd,gen(NULL,cs));
741: }
742:
743: /**************************
744: * Get addressing mode.
745: */
746:
747: unsigned getaddrmode(regm_t idxregs)
748: {
749: unsigned mode;
750:
751: if (I16)
752: {
753: mode = (idxregs & mBX) ? modregrm(2,0,7) : /* [BX] */
754: (idxregs & mDI) ? modregrm(2,0,5): /* [DI] */
755: (idxregs & mSI) ? modregrm(2,0,4): /* [SI] */
756: (assert(0),1);
757: }
758: else
759: { unsigned reg = findreg(idxregs & (ALLREGS | mBP));
760: if (reg == R12)
761: mode = (REX_B << 16) | (modregrm(0,4,4) << 8) | modregrm(2,0,4);
762: else
763: mode = modregrmx(2,0,reg);
764: }
765: return mode;
766: }
767:
768: void setaddrmode(code *c, regm_t idxregs)
769: {
770: unsigned mode = getaddrmode(idxregs);
771: c->Irm = mode & 0xFF;
772: c->Isib = mode >> 8;
773: c->Irex &= ~REX_B;
774: c->Irex |= mode >> 16;
775: }
776:
777: /**********************************************
778: */
779:
780: void getlvalue_msw(code *c)
781: {
782: if (c->IFL1 == FLreg)
783: {
784: unsigned regmsw = c->IEVsym1->Sregmsw;
785: c->Irm = (c->Irm & ~7) | (regmsw & 7);
786: if (regmsw & 8)
787: c->Irex |= REX_B;
788: else
789: c->Irex &= ~REX_B;
790: }
791: else
792: c->IEVoffset1 += REGSIZE;
793: }
794:
795: /**********************************************
796: */
797:
798: void getlvalue_lsw(code *c)
799: {
800: if (c->IFL1 == FLreg)
801: {
802: unsigned reglsw = c->IEVsym1->Sreglsw;
803: c->Irm = (c->Irm & ~7) | (reglsw & 7);
804: if (reglsw & 8)
805: c->Irex |= REX_B;
806: else
807: c->Irex &= ~REX_B;
808: }
809: else
810: c->IEVoffset1 -= REGSIZE;
811: }
812:
813: /******************
814: * Compute addressing mode.
815: * Generate & return sequence of code (if any).
816: * Return in cs the info on it.
817: * Input:
818: * pcs -> where to store data about addressing mode
819: * e -> the lvalue elem
820: * keepmsk mask of registers we must not destroy or use
821: * if (keepmsk & RMstore), this will be only a store operation
822: * into the lvalue
823: * if (keepmsk & RMload), this will be a read operation only
824: */
825:
826: code *getlvalue(code *pcs,elem *e,regm_t keepmsk)
827: { regm_t idxregs;
828: unsigned fl,f,opsave;
829: code *c;
830: elem *e1;
831: elem *e11;
832: elem *e12;
833: bool e1isadd,e1free;
834: unsigned reg;
835: tym_t e1ty;
836: symbol *s;
837:
838: //printf("getlvalue(e = %p)\n",e);
839: //elem_print(e);
840: assert(e);
841: elem_debug(e);
842: if (e->Eoper == OPvar || e->Eoper == OPrelconst)
843: { s = e->EV.sp.Vsym;
844: fl = s->Sfl;
845: if (tyfloating(s->ty()))
846: obj_fltused();
847: }
848: else
849: fl = FLoper;
850: pcs->IFL1 = fl;
851: pcs->Iflags = CFoff; /* only want offsets */
852: pcs->Irex = 0;
853: pcs->IEVoffset1 = 0;
854:
855: tym_t ty = e->Ety;
856: unsigned sz = tysize(ty);
857: if (tyfloating(ty))
858: obj_fltused();
859: if (I64 && (sz == 8 || sz == 16))
860: pcs->Irex |= REX_W;
861: 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?
862: pcs->Iflags |= CFopsize;
863: if (ty & mTYvolatile)
864: pcs->Iflags |= CFvolatile;
865: c = CNIL;
866: switch (fl)
867: {
868: #if 0 && TARGET_LINUX
869: case FLgot:
870: case FLgotoff:
871: gotref = 1;
872: pcs->IEVsym1 = s;
873: pcs->IEVoffset1 = e->EV.sp.Voffset;
874: if (e->Eoper == OPvar && fl == FLgot)
875: {
876: code *c1;
877: unsigned saveop = pcs->Iop;
878: idxregs = allregs & ~keepmsk; // get a scratch register
879: c = allocreg(&idxregs,®,TYptr);
880: pcs->Irm = modregrm(2,reg,BX); // BX has GOT
881: pcs->Isib = 0;
882: //pcs->Iflags |= CFvolatile;
883: pcs->Iop = 0x8B;
884: c = gen(c,pcs); // MOV reg,disp[EBX]
885: pcs->Irm = modregrm(0,0,reg);
886: pcs->IEVoffset1 = 0;
887: pcs->Iop = saveop;
888: }
889: else
890: {
891: pcs->Irm = modregrm(2,0,BX); // disp[EBX] is addr
892: pcs->Isib = 0;
893: }
894: break;
895: #endif
896: case FLoper:
897: #ifdef DEBUG
898: if (debugw) printf("getlvalue(e = %p, km = x%x)\n",e,keepmsk);
899: #endif
900: switch (e->Eoper)
901: {
902: case OPadd: // this way when we want to do LEA
903: e1 = e;
904: e1free = FALSE;
905: e1isadd = TRUE;
906: break;
907: case OPind:
908: case OPpostinc: // when doing (*p++ = ...)
909: case OPpostdec: // when doing (*p-- = ...)
910: case OPbt:
911: case OPbtc:
912: case OPbtr:
913: case OPbts:
914: e1 = e->E1;
915: e1free = TRUE;
916: e1isadd = e1->Eoper == OPadd;
917: break;
918: default:
919: #ifdef DEBUG
920: elem_print(e);
921: #endif
922: assert(0);
923: }
924: e1ty = tybasic(e1->Ety);
925: if (e1isadd)
926: { e12 = e1->E2;
927: e11 = e1->E1;
928: }
929:
930: /* First see if we can replace *(e+&v) with
931: * MOV idxreg,e
932: * EA = [ES:] &v+idxreg
933: */
934: f = FLconst;
935: if (e1isadd &&
936: ((e12->Eoper == OPrelconst && (f = el_fl(e12)) != FLfardata) ||
937: (e12->Eoper == OPconst && !I16 && !e1->Ecount && (!I64 || el_signx32(e12)))) &&
warning C6240: (<expression> && <non-zero constant>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
938: !(I64 && config.flags3 & CFG3pic) &&
939: e1->Ecount == e1->Ecomsub &&
940: (!e1->Ecount || (~keepmsk & ALLREGS & mMSW) || (e1ty != TYfptr && e1ty != TYhptr)) &&
941: tysize(e11->Ety) == REGSIZE
942: )
943: { unsigned char t; /* component of r/m field */
944: int ss;
945: int ssi;
946:
947: /*assert(datafl[f]);*/ /* what if addr of func? */
948: if (!I16)
949: { /* Any register can be an index register */
950: regm_t idxregs = allregs & ~keepmsk;
warning C6246: Local declaration of 'idxregs' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '827' of 'c:\projects\extern\d\dmd\src\backend\cod1.c': Lines: 827
951: assert(idxregs);
952:
953: /* See if e1->E1 can be a scaled index */
954: ss = isscaledindex(e11);
955: if (ss)
956: {
957: /* Load index register with result of e11->E1 */
958: c = cdisscaledindex(e11,&idxregs,keepmsk);
959: reg = findreg(idxregs);
960: #if 0 && TARGET_LINUX
961: if (f == FLgot || f == FLgotoff) // config.flags3 & CFG3pic
962: {
963: gotref = 1;
964: pcs->Irm = modregrm(2,0,4);
965: pcs->Isib = modregrm(ss,reg,BX);
966: }
967: else
968: #endif
969: {
970: t = stackfl[f] ? 2 : 0;
971: pcs->Irm = modregrm(t,0,4);
972: pcs->Isib = modregrm(ss,reg & 7,5);
973: if (reg & 8)
974: pcs->Irex |= REX_X;
975: }
976: }
977: else if ((e11->Eoper == OPmul || e11->Eoper == OPshl) &&
978: !e11->Ecount &&
979: e11->E2->Eoper == OPconst &&
980: (ssi = ssindex(e11->Eoper,e11->E2->EV.Vuns)) != 0
981: )
982: {
983: regm_t scratchm;
984:
985: #if 0 && TARGET_LINUX
986: assert(f != FLgot && f != FLgotoff);
987: #endif
988: char ssflags = ssindex_array[ssi].ssflags;
989: if (ssflags & SSFLnobp && stackfl[f])
990: goto L6;
991:
992: // Load index register with result of e11->E1
993: c = scodelem(e11->E1,&idxregs,keepmsk,TRUE);
994: reg = findreg(idxregs);
995:
996: int ss1 = ssindex_array[ssi].ss1;
997: if (ssflags & SSFLlea)
998: {
999: assert(!stackfl[f]);
1000: pcs->Irm = modregrm(2,0,4);
1001: pcs->Isib = modregrm(ss1,reg & 7,reg & 7);
1002: if (reg & 8)
1003: pcs->Irex |= REX_X | REX_B;
1004: }
1005: else
1006: { int rbase;
1007: unsigned r;
1008:
1009: scratchm = ALLREGS & ~keepmsk;
1010: c = cat(c,allocreg(&scratchm,&r,TYint));
1011:
1012: if (ssflags & SSFLnobase1)
1013: { t = 0;
1014: rbase = 5;
1015: }
1016: else
1017: { t = 0;
1018: rbase = reg;
1019: if (rbase == BP || rbase == R13)
1020: { static unsigned imm32[4] = {1+1,2+1,4+1,8+1};
1021:
1022: // IMUL r,BP,imm32
1023: c = genc2(c,0x69,modregxrmx(3,r,rbase),imm32[ss1]);
1024: goto L7;
1025: }
1026: }
1027:
1028: c = gen2sib(c,0x8D,modregxrm(t,r,4),modregrm(ss1,reg & 7,rbase & 7));
1029: if (reg & 8)
1030: code_orrex(c, REX_X);
1031: if (rbase & 8)
1032: code_orrex(c, REX_B);
1033: if (I64)
1034: code_orrex(c, REX_W);
1035:
1036: if (ssflags & SSFLnobase1)
1037: { code_last(c)->IFL1 = FLconst;
1038: code_last(c)->IEV1.Vuns = 0;
1039: }
1040: L7:
1041: if (ssflags & SSFLnobase)
1042: { t = stackfl[f] ? 2 : 0;
1043: rbase = 5;
1044: }
1045: else
1046: { t = 2;
1047: rbase = r;
1048: assert(rbase != BP);
1049: }
1050: pcs->Irm = modregrm(t,0,4);
1051: pcs->Isib = modregrm(ssindex_array[ssi].ss2,r & 7,rbase & 7);
1052: if (r & 8)
1053: pcs->Irex |= REX_X;
1054: if (rbase & 8)
1055: pcs->Irex |= REX_B;
1056: }
1057: freenode(e11->E2);
1058: freenode(e11);
1059: }
1060: else
1061: {
1062: L6:
1063: /* Load index register with result of e11 */
1064: c = scodelem(e11,&idxregs,keepmsk,TRUE);
1065: setaddrmode(pcs, idxregs);
1066: #if 0 && TARGET_LINUX
1067: if (e12->EV.sp.Vsym->Sfl == FLgot || e12->EV.sp.Vsym->Sfl == FLgotoff)
1068: {
1069: gotref = 1;
1070: #if 1
1071: reg = findreg(idxregs & (ALLREGS | mBP));
1072: pcs->Irm = modregrm(2,0,4);
1073: pcs->Isib = modregrm(0,reg,BX);
1074: #else
1075: pcs->Isib = modregrm(0,pcs->Irm,BX);
1076: pcs->Irm = modregrm(2,0,4);
1077: #endif
1078: }
1079: else
1080: #endif
1081: if (stackfl[f]) /* if we need [EBP] too */
1082: { unsigned idx = pcs->Irm & 7;
1083: if (pcs->Irex & REX_B)
1084: pcs->Irex = (pcs->Irex & ~REX_B) | REX_X;
1085: pcs->Isib = modregrm(0,idx,BP);
1086: pcs->Irm = modregrm(2,0,4);
1087: }
1088: }
1089: }
1090: else
1091: {
1092: idxregs = IDXREGS & ~keepmsk; /* only these can be index regs */
1093: assert(idxregs);
1094: #if 0 && TARGET_LINUX
1095: assert(f != FLgot && f != FLgotoff);
1096: #endif
1097: if (stackfl[f]) /* if stack data type */
1098: { idxregs &= mSI | mDI; /* BX can't index off stack */
1099: if (!idxregs) goto L1; /* index regs aren't avail */
1100: t = 6; /* [BP+SI+disp] */
1101: }
1102: else
1103: t = 0; /* [SI + disp] */
1104: c = scodelem(e11,&idxregs,keepmsk,TRUE); /* load idx reg */
1105: pcs->Irm = getaddrmode(idxregs) ^ t;
1106: }
1107: if (f == FLpara)
1108: refparam = TRUE;
1109: else if (f == FLauto || f == FLtmp || f == FLbprel || f == FLfltreg)
1110: reflocal = TRUE;
1111: else if (f == FLcsdata || tybasic(e12->Ety) == TYcptr)
1112: pcs->Iflags |= CFcs;
1113: else
1114: assert(f != FLreg);
1115: pcs->IFL1 = f;
1116: if (f != FLconst)
1117: pcs->IEVsym1 = e12->EV.sp.Vsym;
1118: pcs->IEVoffset1 = e12->EV.sp.Voffset; /* += ??? */
1119:
1120: /* If e1 is a CSE, we must generate an addressing mode */
1121: /* but also leave EA in registers so others can use it */
1122: if (e1->Ecount)
1123: { unsigned flagsave;
1124:
1125: idxregs = IDXREGS & ~keepmsk;
1126: c = cat(c,allocreg(&idxregs,®,TYoffset));
1127:
1128: /* If desired result is a far pointer, we'll have */
1129: /* to load another register with the segment of v */
1130: if (e1ty == TYfptr)
1131: {
1132: unsigned msreg;
1133:
1134: idxregs |= mMSW & ALLREGS & ~keepmsk;
1135: c = cat(c,allocreg(&idxregs,&msreg,TYfptr));
1136: msreg = findregmsw(idxregs);
1137: /* MOV msreg,segreg */
1138: c = genregs(c,0x8C,segfl[f],msreg);
1139: }
1140: opsave = pcs->Iop;
1141: flagsave = pcs->Iflags;
1142: pcs->Iop = 0x8D;
1143: code_newreg(pcs, reg);
1144: if (!I16)
1145: pcs->Iflags &= ~CFopsize;
1146: if (I64)
1147: pcs->Irex |= REX_W;
1148: c = gen(c,pcs); /* LEA idxreg,EA */
1149: cssave(e1,idxregs,TRUE);
1150: if (!I16)
1151: pcs->Iflags = flagsave;
1152: if (stackfl[f] && (config.wflags & WFssneds)) // if pointer into stack
1153: pcs->Iflags |= CFss; // add SS: override
1154: pcs->Iop = opsave;
1155: pcs->IFL1 = FLoffset;
1156: pcs->IEV1.Vuns = 0;
1157: setaddrmode(pcs, idxregs);
1158: }
1159: freenode(e12);
1160: if (e1free)
1161: freenode(e1);
1162: goto Lptr;
1163: }
1164:
1165: L1:
1166:
1167: /* The rest of the cases could be a far pointer */
1168:
1169: idxregs = (I16 ? IDXREGS : allregs) & ~keepmsk; // only these can be index regs
1170: assert(idxregs);
1171: if (!I16 &&
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
1172: (sz == REGSIZE || (I64 && sz == 4)) &&
1173: keepmsk & RMstore)
1174: idxregs |= regcon.mvar;
1175:
1176: #if !TARGET_FLAT
1177: switch (e1ty)
1178: { case TYfptr: /* if far pointer */
1179: case TYhptr:
1180: idxregs = (mES | IDXREGS) & ~keepmsk; // need segment too
1181: assert(idxregs & mES);
1182: pcs->Iflags |= CFes; /* ES segment override */
1183: break;
1184: case TYsptr: /* if pointer to stack */
1185: if (config.wflags & WFssneds) // if SS != DS
1186: pcs->Iflags |= CFss; /* then need SS: override */
1187: break;
1188: case TYcptr: /* if pointer to code */
1189: pcs->Iflags |= CFcs; /* then need CS: override */
1190: break;
1191: }
1192: #endif
1193: pcs->IFL1 = FLoffset;
1194: pcs->IEV1.Vuns = 0;
1195:
1196: /* see if we can replace *(e+c) with
1197: * MOV idxreg,e
1198: * [MOV ES,segment]
1199: * EA = [ES:]c[idxreg]
1200: */
1201: if (e1isadd && e12->Eoper == OPconst &&
1202: (!I64 || el_signx32(e12)) &&
1203: (tysize(e12->Ety) == REGSIZE || (I64 && tysize(e12->Ety) == 4)) &&
1204: (!e1->Ecount || !e1free)
1205: )
1206: { int ss;
1207:
1208: pcs->IEV1.Vuns = e12->EV.Vuns;
1209: freenode(e12);
1210: if (e1free) freenode(e1);
1211: if (!I16 && e11->Eoper == OPadd && !e11->Ecount &&
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
1212: tysize(e11->Ety) == REGSIZE)
1213: {
1214: e12 = e11->E2;
1215: e11 = e11->E1;
1216: e1 = e1->E1;
1217: e1free = TRUE;
1218: goto L4;
1219: }
1220: if (!I16 && (ss = isscaledindex(e11)) != 0)
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
1221: { // (v * scale) + const
1222: c = cdisscaledindex(e11,&idxregs,keepmsk);
1223: reg = findreg(idxregs);
1224: pcs->Irm = modregrm(0,0,4);
1225: pcs->Isib = modregrm(ss,reg & 7,5);
1226: if (reg & 8)
1227: pcs->Irex |= REX_X;
1228: }
1229: else
1230: {
1231: c = scodelem(e11,&idxregs,keepmsk,TRUE); // load index reg
1232: setaddrmode(pcs, idxregs);
1233: }
1234: goto Lptr;
1235: }
1236:
1237: /* Look for *(v1 + v2)
1238: * EA = [v1][v2]
1239: */
1240:
1241: if (!I16 && e1isadd && (!e1->Ecount || !e1free) &&
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
1242: (tysize[e1ty] == REGSIZE || (I64 && tysize[e1ty] == 4)))
1243: { code *c2;
1244: regm_t idxregs2;
1245: unsigned base,index;
1246: int ss;
1247:
1248: L4:
1249: // Look for *(v1 + v2 << scale)
1250: ss = isscaledindex(e12);
1251: if (ss)
1252: {
1253: c = scodelem(e11,&idxregs,keepmsk,TRUE);
1254: idxregs2 = allregs & ~(idxregs | keepmsk);
1255: c2 = cdisscaledindex(e12,&idxregs2,keepmsk | idxregs);
1256: }
1257:
1258: // Look for *(v1 << scale + v2)
1259: else if ((ss = isscaledindex(e11)) != 0)
1260: {
1261: idxregs2 = idxregs;
1262: c = cdisscaledindex(e11,&idxregs2,keepmsk);
1263: idxregs = allregs & ~(idxregs2 | keepmsk);
1264: c2 = scodelem(e12,&idxregs,keepmsk | idxregs2,TRUE);
1265: }
1266: // Look for *(((v1 << scale) + c1) + v2)
1267: else if (e11->Eoper == OPadd && !e11->Ecount &&
1268: e11->E2->Eoper == OPconst &&
1269: (ss = isscaledindex(e11->E1)) != 0
1270: )
1271: {
1272: pcs->IEV1.Vuns = e11->E2->EV.Vuns;
1273: idxregs2 = idxregs;
1274: c = cdisscaledindex(e11->E1,&idxregs2,keepmsk);
1275: idxregs = allregs & ~(idxregs2 | keepmsk);
1276: c2 = scodelem(e12,&idxregs,keepmsk | idxregs2,TRUE);
1277: freenode(e11->E2);
1278: freenode(e11);
1279: }
1280: else
1281: {
1282: c = scodelem(e11,&idxregs,keepmsk,TRUE);
1283: idxregs2 = allregs & ~(idxregs | keepmsk);
1284: c2 = scodelem(e12,&idxregs2,keepmsk | idxregs,TRUE);
1285: }
1286: c = cat(c,c2);
1287: base = findreg(idxregs);
1288: index = findreg(idxregs2);
1289: pcs->Irm = modregrm(2,0,4);
1290: pcs->Isib = modregrm(ss,index & 7,base & 7);
1291: if (index & 8)
1292: pcs->Irex |= REX_X;
1293: if (base & 8)
1294: pcs->Irex |= REX_B;
1295: if (e1free) freenode(e1);
1296: goto Lptr;
1297: }
1298:
1299: /* give up and replace *e1 with
1300: * MOV idxreg,e
1301: * EA = 0[idxreg]
1302: * pinholeopt() will usually correct the 0, we need it in case
1303: * we have a pointer to a long and need an offset to the second
1304: * word.
1305: */
1306:
1307: assert(e1free);
1308: c = scodelem(e1,&idxregs,keepmsk,TRUE); /* load index register */
1309: setaddrmode(pcs, idxregs);
1310: Lptr:
1311: if (config.flags3 & CFG3ptrchk)
1312: cod3_ptrchk(&c,pcs,keepmsk); // validate pointer code
1313: break;
1314: case FLdatseg:
1315: assert(0);
1316: #if 0
1317: pcs->Irm = modregrm(0,0,BPRM);
1318: pcs->IEVpointer1 = e->EVpointer;
1319: break;
1320: #endif
1321: case FLfltreg:
1322: reflocal = TRUE;
1323: pcs->Irm = modregrm(2,0,BPRM);
1324: pcs->IEV1.Vint = 0;
1325: break;
1326: case FLreg:
1327: goto L2;
1328: case FLpara:
1329: refparam = TRUE;
1330: pcs->Irm = modregrm(2,0,BPRM);
1331: goto L2;
1332:
1333: case FLauto:
1334: if (s->Sclass == SCfastpar && regcon.params & mask[s->Spreg])
1335: {
1336: if (keepmsk & RMload)
1337: {
1338: if (sz == REGSIZE) // could this be (sz <= REGSIZE) ?
1339: {
1340: pcs->Irm = modregrm(3,0,s->Spreg & 7);
1341: if (s->Spreg & 8)
1342: pcs->Irex |= REX_B;
1343: regcon.used |= mask[s->Spreg];
1344: break;
1345: }
1346: }
1347: else
1348: regcon.params &= ~mask[s->Spreg];
1349: }
1350: case FLtmp:
1351: case FLbprel:
1352: reflocal = TRUE;
1353: pcs->Irm = modregrm(2,0,BPRM);
1354: goto L2;
1355: case FLextern:
1356: if (s->Sident[0] == '_' && memcmp(s->Sident + 1,"tls_array",10) == 0)
1357: {
1358: #if TARGET_LINUX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
1359: // Rewrite as GS:[0000], or FS:[0000] for 64 bit
1360: if (I64)
1361: {
1362: pcs->Irm = modregrm(0, 0, 4);
1363: pcs->Isib = modregrm(0, 4, 5); // don't use [RIP] addressing
1364: pcs->IFL1 = FLconst;
1365: pcs->IEV1.Vuns = 0;
1366: pcs->Iflags = CFfs;
1367: pcs->Irex |= REX_W;
1368: }
1369: else
1370: {
1371: pcs->Irm = modregrm(0, 0, BPRM);
1372: pcs->IFL1 = FLconst;
1373: pcs->IEV1.Vuns = 0;
1374: pcs->Iflags = CFgs;
1375: }
1376: break;
1377: #else
1378: pcs->Iflags |= CFfs; // add FS: override
1379: #endif
1380: }
1381: if (s->ty() & mTYcs && LARGECODE)
1382: goto Lfardata;
1383: goto L3;
1384: case FLdata:
1385: case FLudata:
1386: case FLcsdata:
1387: #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
1388: case FLgot:
1389: case FLgotoff:
1390: case FLtlsdata:
1391: #endif
1392: L3:
1393: pcs->Irm = modregrm(0,0,BPRM);
1394: L2:
1395: if (fl == FLreg)
1396: { assert(s->Sregm & regcon.mvar);
1397: if (
1398: s->Sclass == SCregpar ||
1399: s->Sclass == SCparameter)
1400: { refparam = TRUE;
1401: reflocal = TRUE; // kludge to set up prolog
1402: }
1403: pcs->Irm = modregrm(3,0,s->Sreglsw & 7);
1404: if (s->Sreglsw & 8)
1405: pcs->Irex |= REX_B;
1406: if (e->EV.sp.Voffset == 1 && sz == 1)
1407: { assert(s->Sregm & BYTEREGS);
1408: assert(s->Sreglsw < 4);
1409: pcs->Irm |= 4; // use 2nd byte of register
1410: }
1411: else
1412: { assert(!e->EV.sp.Voffset);
1413: if (I64 && sz == 1 && s->Sreglsw >= 4)
1414: pcs->Irex |= REX;
1415: }
1416: }
1417: else if (s->ty() & mTYcs && !(fl == FLextern && LARGECODE))
1418: {
1419: pcs->Iflags |= CFcs | CFoff;
1420: }
1421: #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
1422: if (I64 && config.flags3 & CFG3pic &&
1423: (fl == FLtlsdata || s->ty() & mTYthread))
1424: {
1425: pcs->Iflags |= CFopsize;
1426: pcs->Irex = 0x48;
1427: }
1428: #endif
1429: pcs->IEVsym1 = s;
1430: pcs->IEVoffset1 = e->EV.sp.Voffset;
1431: if (sz == 1)
1432: { /* Don't use SI or DI for this variable */
1433: s->Sflags |= GTbyte;
1434: if (e->EV.sp.Voffset > 1)
1435: s->Sflags &= ~GTregcand;
1436: }
1437: else if (e->EV.sp.Voffset)
1438: s->Sflags &= ~GTregcand;
1439: if (!(keepmsk & RMstore)) // if not store only
1440: { s->Sflags |= SFLread; // assume we are doing a read
1441: }
1442: break;
1443: case FLpseudo:
1444: #if MARS
1445: assert(0);
1446: #else
1447: {
1448: unsigned u = s->Sreglsw;
1449: c = getregs(pseudomask[u]);
1450: pcs->Irm = modregrm(3,0,pseudoreg[u] & 7);
1451: break;
1452: }
1453: #endif
1454: case FLfardata:
1455: assert(!TARGET_FLAT);
1456: case FLfunc: /* reading from code seg */
1457: if (config.exe & EX_flat)
1458: goto L3;
1459: Lfardata:
1460: {
1461: regm_t regm = ALLREGS & ~keepmsk; // need scratch register
1462: code *c1 = allocreg(®m,®,TYint);
1463: /* MOV mreg,seg of symbol */
1464: c = gencs(CNIL,0xB8 + reg,0,FLextern,s);
1465: c->Iflags = CFseg;
1466: c = gen2(c,0x8E,modregrmx(3,0,reg)); /* MOV ES,reg */
1467: c = cat3(c1,getregs(mES),c);
1468: pcs->Iflags |= CFes | CFoff; /* ES segment override */
1469: goto L3;
1470: }
1471:
1472: case FLstack:
1473: assert(!I16);
1474: pcs->Irm = modregrm(2,0,4);
1475: pcs->Isib = modregrm(0,4,SP);
1476: pcs->IEVsym1 = s;
1477: pcs->IEVoffset1 = e->EV.sp.Voffset;
1478: break;
1479:
1480: default:
1481: #ifdef DEBUG
1482: WRFL((enum FL)fl);
1483: symbol_print(s);
1484: #endif
1485: assert(0);
1486: }
1487: return c;
1488: }
1489:
1490: /*******************************
1491: * Same as codelem(), but do not destroy the registers in keepmsk.
1492: * Use scratch registers as much as possible, then use stack.
1493: * Input:
1494: * constflag TRUE if user of result will not modify the
1495: * registers returned in *pretregs.
1496: */
1497:
1498: code *scodelem(elem *e,regm_t *pretregs,regm_t keepmsk,bool constflag)
1499: { code *c,*cs1,*cs2,*cs3;
1500: unsigned i,j;
1501: regm_t oldmfuncreg,oldregcon,oldregimmed,overlap,tosave,touse;
1502: int adjesp;
1503: unsigned stackpushsave;
1504: char calledafuncsave;
1505:
1506: #ifdef DEBUG
1507: if (debugw)
1508: printf("+scodelem(e=%p *pretregs=%s keepmsk=%s constflag=%d\n",
1509: e,regm_str(*pretregs),regm_str(keepmsk),constflag);
1510: #endif
1511: elem_debug(e);
1512: if (constflag)
1513: { regm_t regm;
1514: unsigned reg;
1515:
1516: if (isregvar(e,®m,®) && // if e is a register variable
1517: (regm & *pretregs) == regm && // in one of the right regs
1518: e->EV.sp.Voffset == 0
1519: )
1520: {
1521: unsigned sz1 = tysize(e->Ety);
1522: unsigned sz2 = tysize(e->EV.sp.Vsym->Stype->Tty);
1523: if (sz1 <= REGSIZE && sz2 > REGSIZE)
warning C4018: '<=' : signed/unsigned mismatch
warning C4018: '>' : signed/unsigned mismatch
1524: regm &= mLSW;
1525: c = fixresult(e,regm,pretregs);
1526: cssave(e,regm,0);
1527: freenode(e);
1528: #ifdef DEBUG
1529: if (debugw)
1530: printf("-scodelem(e=%p *pretregs=x%x keepmsk=x%x constflag=%d\n",
1531: e,*pretregs,keepmsk,constflag);
1532: #endif
1533: return c;
1534: }
1535: }
1536: overlap = msavereg & keepmsk;
1537: msavereg |= keepmsk; /* add to mask of regs to save */
1538: oldregcon = regcon.cse.mval;
1539: oldregimmed = regcon.immed.mval;
1540: oldmfuncreg = mfuncreg; /* remember old one */
1541: mfuncreg = (mBP | mES | ALLREGS) & ~regcon.mvar;
1542: stackpushsave = stackpush;
1543: #if 0
1544: if (keepmsk)
1545: stackpush++; /* assume we'll have to save stuff on stack */
1546: #endif
1547: calledafuncsave = calledafunc;
1548: calledafunc = 0;
1549: c = codelem(e,pretregs,constflag); /* generate code for the elem */
1550: #if 0
1551: if (keepmsk)
1552: stackpush--;
1553: #endif
1554:
1555: tosave = keepmsk & ~msavereg; /* registers to save */
1556: if (tosave)
1557: { cgstate.stackclean++;
1558: c = genstackclean(c,stackpush - stackpushsave,*pretregs | msavereg);
1559: cgstate.stackclean--;
1560: }
1561:
1562: /* Assert that no new CSEs are generated that are not reflected */
1563: /* in mfuncreg. */
1564: #ifdef DEBUG
1565: if ((mfuncreg & (regcon.cse.mval & ~oldregcon)) != 0)
1566: printf("mfuncreg x%x, regcon.cse.mval x%x, oldregcon x%x, regcon.mvar x%x\n",
1567: mfuncreg,regcon.cse.mval,oldregcon,regcon.mvar);
1568: #endif
1569: assert((mfuncreg & (regcon.cse.mval & ~oldregcon)) == 0);
1570:
1571: /* bugzilla 3521
1572: * The problem is:
1573: * reg op (reg = exp)
1574: * where reg must be preserved (in keepregs) while the expression to be evaluated
1575: * must change it.
1576: * The only solution is to make this variable not a register.
1577: */
1578: if (regcon.mvar & tosave)
1579: {
1580: //elem_print(e);
1581: //printf("test1: regcon.mvar x%x tosave x%x\n", regcon.mvar, tosave);
1582: cgreg_unregister(regcon.mvar & tosave);
1583: }
1584:
1585: /* which registers can we use to save other registers in? */
1586: if (config.flags4 & CFG4space || // if optimize for space
1587: config.target_cpu >= TARGET_80486) // PUSH/POP ops are 1 cycle
1588: touse = 0; // PUSH/POP pairs are always shorter
1589: else
1590: { touse = mfuncreg & allregs & ~(msavereg | oldregcon | regcon.cse.mval);
1591: /* Don't use registers we'll have to save/restore */
1592: touse &= ~(fregsaved & oldmfuncreg);
1593: /* Don't use registers that have constant values in them, since
1594: the code generated might have used the value.
1595: */
1596: touse &= ~oldregimmed;
1597: }
1598:
1599: cs1 = cs2 = cs3 = NULL;
1600: adjesp = 0;
1601:
1602: for (i = 0; tosave; i++)
1603: { regm_t mi = mask[i];
1604:
1605: assert(i < REGMAX);
1606: if (mi & tosave) /* i = register to save */
1607: {
1608: if (touse) /* if any scratch registers */
1609: { for (j = 0; j < 8; j++)
1610: { regm_t mj = mask[j];
1611:
1612: if (touse & mj)
1613: { cs1 = genmovreg(cs1,j,i);
1614: cs2 = cat(genmovreg(CNIL,i,j),cs2);
1615: touse &= ~mj;
1616: mfuncreg &= ~mj;
1617: regcon.used |= mj;
1618: break;
1619: }
1620: }
1621: assert(j < 8);
1622: }
1623: else /* else use stack */
1624: #if 0
1625: { int push,pop;
1626:
1627: stackchanged = 1;
1628: adjesp += REGSIZE;
1629: if (i == ES)
1630: { push = 0x06;
1631: pop = 0x07;
1632: }
1633: else
1634: { push = 0x50 + i;
1635: pop = push | 8;
1636: }
1637: cs1 = gen1(cs1,push); /* PUSH i */
1638: cs2 = cat(gen1(CNIL,pop),cs2); /* POP i */
1639: }
1640: #else
1641: {
1642: stackchanged = 1;
1643: adjesp += REGSIZE;
1644: gensaverestore2(mask[i], &cs1, &cs2);
1645: }
1646: #endif
1647: cs3 = cat(getregs(mi),cs3);
1648: tosave &= ~mi;
1649: }
1650: }
1651: if (adjesp)
1652: {
1653: // If this is done an odd number of times, it
1654: // will throw off the 8 byte stack alignment.
1655: // We should *only* worry about this if a function
1656: // was called in the code generation by codelem().
1657: int sz;
1658: if (STACKALIGN == 16)
1659: sz = -(adjesp & (STACKALIGN - 1)) & (STACKALIGN - 1);
1660: else
1661: sz = -(adjesp & 7) & 7;
1662: if (calledafunc && !I16 && sz && (STACKALIGN == 16 || config.flags4 & CFG4stackalign))
warning C6240: (<expression> && <non-zero constant>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
1663: {
1664: unsigned grex = I64 ? REX_W << 16 : 0;
1665: regm_t mval_save = regcon.immed.mval;
1666: regcon.immed.mval = 0; // prevent reghasvalue() optimizations
1667: // because c hasn't been executed yet
1668: cs1 = genc2(cs1,0x81,grex | modregrm(3,5,SP),sz); // SUB ESP,sz
1669: if (I64)
1670: code_orrex(cs1, REX_W);
1671: regcon.immed.mval = mval_save;
1672: cs1 = genadjesp(cs1, sz);
1673:
1674: code *cx = genc2(CNIL,0x81,grex | modregrm(3,0,SP),sz); // ADD ESP,sz
1675: if (I64)
1676: code_orrex(cx, REX_W);
1677: cx = genadjesp(cx, -sz);
1678: cs2 = cat(cx, cs2);
1679: }
1680:
1681: cs1 = genadjesp(cs1,adjesp);
1682: cs2 = genadjesp(cs2,-adjesp);
1683: }
1684:
1685: calledafunc |= calledafuncsave;
1686: msavereg &= ~keepmsk | overlap; /* remove from mask of regs to save */
1687: mfuncreg &= oldmfuncreg; /* update original */
1688: #ifdef DEBUG
1689: if (debugw)
1690: printf("-scodelem(e=%p *pretregs=x%x keepmsk=x%x constflag=%d\n",
1691: e,*pretregs,keepmsk,constflag);
1692: #endif
1693: return cat4(cs1,c,cs3,cs2);
1694: }
1695:
1696:
1697: /*****************************
1698: * Given an opcode and EA in cs, generate code
1699: * for each floating register in turn.
1700: * Input:
1701: * tym either TYdouble or TYfloat
1702: */
1703:
1704: code *fltregs(code *pcs,tym_t tym)
1705: { code *c;
1706:
1707: assert(!I64);
1708: tym = tybasic(tym);
1709: if (I32)
1710: {
1711: c = getregs((tym == TYfloat) ? mAX : mAX | mDX);
1712: if (tym != TYfloat)
1713: {
1714: pcs->IEVoffset1 += REGSIZE;
1715: NEWREG(pcs->Irm,DX);
1716: c = gen(c,pcs);
1717: pcs->IEVoffset1 -= REGSIZE;
1718: }
1719: NEWREG(pcs->Irm,AX);
1720: c = gen(c,pcs);
1721: }
1722: else
1723: {
1724: c = getregs((tym == TYfloat) ? FLOATREGS_16 : DOUBLEREGS_16);
1725: pcs->IEVoffset1 += (tym == TYfloat) ? 2 : 6;
1726: if (tym == TYfloat)
1727: NEWREG(pcs->Irm,DX);
1728: else
1729: NEWREG(pcs->Irm,AX);
1730: c = gen(c,pcs);
1731: pcs->IEVoffset1 -= 2;
1732: if (tym == TYfloat)
1733: NEWREG(pcs->Irm,AX);
1734: else
1735: NEWREG(pcs->Irm,BX);
1736: gen(c,pcs);
1737: if (tym != TYfloat)
1738: { pcs->IEVoffset1 -= 2;
1739: NEWREG(pcs->Irm,CX);
1740: gen(c,pcs);
1741: pcs->IEVoffset1 -= 2; /* note that exit is with Voffset unaltered */
1742: NEWREG(pcs->Irm,DX);
1743: gen(c,pcs);
1744: }
1745: }
1746: return c;
1747: }
1748:
1749:
1750: /*****************************
1751: * Given a result in registers, test it for TRUE or FALSE.
1752: * Will fail if TYfptr and the reg is ES!
1753: * If saveflag is TRUE, preserve the contents of the
1754: * registers.
1755: */
1756:
1757: code *tstresult(regm_t regm,tym_t tym,unsigned saveflag)
1758: {
1759: unsigned scrreg; /* scratch register */
1760: regm_t scrregm;
1761:
1762: #ifdef DEBUG
1763: if (!(regm & (mBP | ALLREGS)))
1764: printf("tstresult(regm = %s, tym = x%x, saveflag = %d)\n",
1765: regm_str(regm),tym,saveflag);
1766: #endif
1767: assert(regm & (XMMREGS | mBP | ALLREGS));
1768: tym = tybasic(tym);
1769: code *ce = CNIL;
1770: unsigned reg = findreg(regm);
1771: unsigned sz = tysize[tym];
1772: if (sz == 1)
1773: { assert(regm & BYTEREGS);
1774: ce = genregs(ce,0x84,reg,reg); // TEST regL,regL
1775: if (I64 && reg >= 4)
1776: code_orrex(ce, REX);
1777: return ce;
1778: }
1779: if (regm & XMMREGS)
1780: {
1781: unsigned xreg;
1782: regm_t xregs = XMMREGS & ~regm;
1783: ce = allocreg(&xregs, &xreg, TYdouble);
1784: unsigned op = 0;
1785: if (tym == TYdouble || tym == TYidouble || tym == TYcdouble)
1786: op = 0x660000;
1787: ce = gen2(ce,op | 0x0F57,modregrm(3,xreg-XMM0,xreg-XMM0)); // XORPS xreg,xreg
1788: gen2(ce,op | 0x0F2E,modregrm(3,xreg-XMM0,reg-XMM0)); // UCOMISS xreg,reg
1789: if (tym == TYcfloat || tym == TYcdouble)
1790: { code *cnop = gennop(CNIL);
1791: genjmp(ce,JNE,FLcode,(block *) cnop); // JNE L1
1792: genjmp(ce,JP, FLcode,(block *) cnop); // JP L1
1793: reg = findreg(regm & ~mask[reg]);
1794: gen2(ce,op | 0x0F2E,modregrm(3,xreg-XMM0,reg-XMM0)); // UCOMISS xreg,reg
1795: ce = cat(ce, cnop);
1796: }
1797: return ce;
1798: }
1799: if (sz <= REGSIZE)
warning C4018: '<=' : signed/unsigned mismatch
1800: {
1801: if (!I16)
1802: {
1803: if (tym == TYfloat)
1804: { if (saveflag)
1805: {
1806: scrregm = allregs & ~regm; /* possible scratch regs */
1807: ce = allocreg(&scrregm,&scrreg,TYoffset); /* allocate scratch reg */
1808: ce = genmovreg(ce,scrreg,reg); /* MOV scrreg,msreg */
1809: reg = scrreg;
1810: }
1811: ce = cat(ce,getregs(mask[reg]));
1812: return gen2(ce,0xD1,modregrmx(3,4,reg)); // SHL reg,1
1813: }
1814: ce = gentstreg(ce,reg); // TEST reg,reg
1815: if (sz == SHORTSIZE)
1816: ce->Iflags |= CFopsize; /* 16 bit operands */
1817: else if (sz == 8)
1818: code_orrex(ce, REX_W);
1819: }
1820: else
1821: ce = gentstreg(ce,reg); // TEST reg,reg
1822: return ce;
1823: }
1824: if (saveflag || tyfv(tym))
1825: {
1826: scrregm = ALLREGS & ~regm; /* possible scratch regs */
1827: ce = allocreg(&scrregm,&scrreg,TYoffset); /* allocate scratch reg */
1828: if (I32 || sz == REGSIZE * 2)
1829: { code *c;
1830:
1831: assert(regm & mMSW && regm & mLSW);
1832:
1833: reg = findregmsw(regm);
1834: if (I32)
1835: {
1836: if (tyfv(tym))
1837: { c = genregs(CNIL,0x0FB7,scrreg,reg); // MOVZX scrreg,msreg
1838: ce = cat(ce,c);
1839: }
1840: else
1841: { ce = genmovreg(ce,scrreg,reg); /* MOV scrreg,msreg */
1842: if (tym == TYdouble || tym == TYdouble_alias)
1843: gen2(ce,0xD1,modregrm(3,4,scrreg)); /* SHL scrreg,1 */
1844: }
1845: }
1846: else
1847: {
1848: ce = genmovreg(ce,scrreg,reg); /* MOV scrreg,msreg */
1849: if (tym == TYfloat)
1850: gen2(ce,0xD1,modregrm(3,4,scrreg)); /* SHL scrreg,1 */
1851: }
1852: reg = findreglsw(regm);
1853: genorreg(ce,scrreg,reg); /* OR scrreg,lsreg */
1854: }
1855: else if (sz == 8)
1856: { /* !I32 */
1857: ce = genmovreg(ce,scrreg,AX); /* MOV scrreg,AX */
1858: if (tym == TYdouble || tym == TYdouble_alias)
1859: gen2(ce,0xD1,modregrm(3,4,scrreg)); // SHL scrreg,1
1860: genorreg(ce,scrreg,BX); /* OR scrreg,BX */
1861: genorreg(ce,scrreg,CX); /* OR scrreg,CX */
1862: genorreg(ce,scrreg,DX); /* OR scrreg,DX */
1863: }
1864: else
1865: assert(0);
1866: }
1867: else
1868: {
1869: if (I32 || sz == REGSIZE * 2)
1870: {
1871: /* can't test ES:LSW for 0 */
1872: assert(regm & mMSW & ALLREGS && regm & (mLSW | mBP));
1873:
1874: reg = findregmsw(regm);
1875: ce = getregs(mask[reg]); /* we're going to trash reg */
1876: if (tyfloating(tym) && sz == 2 * intsize)
1877: ce = gen2(ce,0xD1,modregrm(3,4,reg)); // SHL reg,1
1878: ce = genorreg(ce,reg,findreglsw(regm)); // OR reg,reg+1
1879: }
1880: else if (sz == 8)
1881: { assert(regm == DOUBLEREGS_16);
1882: ce = getregs(mAX); // allocate AX
1883: if (tym == TYdouble || tym == TYdouble_alias)
1884: ce = gen2(ce,0xD1,modregrm(3,4,AX)); // SHL AX,1
1885: genorreg(ce,AX,BX); // OR AX,BX
1886: genorreg(ce,AX,CX); // OR AX,CX
1887: genorreg(ce,AX,DX); // OR AX,DX
1888: }
1889: else
1890: assert(0);
1891: }
1892: code_orflag(ce,CFpsw);
1893: return ce;
1894: }
1895:
1896:
1897: /******************************
1898: * Given the result of an expression is in retregs,
1899: * generate necessary code to return result in *pretregs.
1900: */
1901:
1902: code *fixresult(elem *e,regm_t retregs,regm_t *pretregs)
1903: { code *c,*ce;
1904: unsigned reg,rreg;
1905: regm_t forccs,forregs;
1906: tym_t tym;
1907: int sz;
1908:
1909: //printf("fixresult(e = %p, retregs = %s, *pretregs = %s)\n",e,regm_str(retregs),regm_str(*pretregs));
1910: if (*pretregs == 0) return CNIL; /* if don't want result */
1911: assert(e && retregs); /* need something to work with */
1912: forccs = *pretregs & mPSW;
1913: forregs = *pretregs & (mST01 | mST0 | mBP | ALLREGS | mES | mSTACK | XMMREGS);
1914: tym = tybasic(e->Ety);
1915: #if 0
1916: if (tym == TYstruct)
1917: // Hack to support cdstreq()
1918: tym = TYfptr;
1919: #else
1920: if (tym == TYstruct)
1921: // Hack to support cdstreq()
1922: tym = (forregs & mMSW) ? TYfptr : TYnptr;
1923: #endif
1924: c = CNIL;
1925: sz = tysize[tym];
1926: if (sz == 1)
1927: {
1928: assert(retregs & BYTEREGS);
1929: unsigned reg = findreg(retregs);
warning C6246: Local declaration of 'reg' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '1904' of 'c:\projects\extern\d\dmd\src\backend\cod1.c': Lines: 1904
1930: if (e->Eoper == OPvar &&
1931: e->EV.sp.Voffset == 1 &&
1932: e->EV.sp.Vsym->Sfl == FLreg)
1933: {
1934: assert(reg < 4);
1935: if (forccs)
1936: c = gen2(c,0x84,modregrm(3,reg | 4,reg | 4)); // TEST regH,regH
1937: forccs = 0;
1938: }
1939: }
1940: if ((retregs & forregs) == retregs) /* if already in right registers */
1941: *pretregs = retregs;
1942: else if (forregs) /* if return the result in registers */
1943: {
1944: if (forregs & (mST01 | mST0))
1945: return fixresult87(e,retregs,pretregs);
1946: ce = CNIL;
1947: unsigned opsflag = FALSE;
1948: if (I16 && sz == 8)
1949: { if (forregs & mSTACK)
1950: { assert(retregs == DOUBLEREGS_16);
1951: /* Push floating regs */
1952: c = CNIL;
1953: ce = gen1(ce,0x50 + AX);
1954: gen1(ce,0x50 + BX);
1955: gen1(ce,0x50 + CX);
1956: gen1(ce,0x50 + DX);
1957: stackpush += DOUBLESIZE;
1958: }
1959: else if (retregs & mSTACK)
1960: { assert(forregs == DOUBLEREGS_16);
1961: /* Pop floating regs */
1962: c = getregs(forregs);
1963: ce = gen1(ce,0x58 + DX);
1964: gen1(ce,0x58 + CX);
1965: gen1(ce,0x58 + BX);
1966: gen1(ce,0x58 + AX);
1967: stackpush -= DOUBLESIZE;
1968: retregs = DOUBLEREGS_16; /* for tstresult() below */
1969: }
1970: else
1971: #ifdef DEBUG
1972: printf("retregs = x%x, forregs = x%x\n",retregs,forregs),
1973: #endif
1974: assert(0);
1975: if (EOP(e))
1976: opsflag = TRUE;
1977: }
1978: else
1979: {
1980: c = allocreg(pretregs,&rreg,tym); /* allocate return regs */
1981: if (sz > REGSIZE)
1982: {
1983: unsigned msreg = findregmsw(retregs);
1984: unsigned lsreg = findreglsw(retregs);
1985: unsigned msrreg = findregmsw(*pretregs);
1986: unsigned lsrreg = findreglsw(*pretregs);
1987:
1988: ce = genmovreg(ce,msrreg,msreg); /* MOV msrreg,msreg */
1989: ce = genmovreg(ce,lsrreg,lsreg); /* MOV lsrreg,lsreg */
1990: }
1991: else if (retregs & XMMREGS)
1992: {
1993: reg = findreg(retregs & XMMREGS);
1994: // MOVSD floatreg, XMM?
1995: ce = genfltreg(ce,0xF20F11,reg - XMM0,0);
1996: if (mask[rreg] & XMMREGS)
1997: // MOVSD XMM?, floatreg
1998: ce = genfltreg(ce,0xF20F10,rreg - XMM0,0);
1999: else
2000: {
2001: // MOV rreg,floatreg
2002: ce = genfltreg(ce,0x8B,rreg,0);
2003: if (sz == 8)
2004: code_orrex(ce,REX_W);
2005: }
2006: }
2007: else if (forregs & XMMREGS)
2008: {
2009: reg = findreg(retregs & (mBP | ALLREGS));
2010: // MOV floatreg,reg
2011: ce = genfltreg(ce,0x89,reg,0);
2012: if (sz == 8)
2013: code_orrex(ce,REX_W);
2014: // MOVSS/MOVSD XMMreg,floatreg
2015: ce = genfltreg(ce,0xF20F10,rreg - XMM0,0);
2016: }
2017: else
2018: {
2019: assert(!(retregs & XMMREGS));
2020: assert(!(forregs & XMMREGS));
2021: reg = findreg(retregs & (mBP | ALLREGS));
2022: ce = genmovreg(ce,rreg,reg); /* MOV rreg,reg */
2023: }
2024: }
2025: c = cat(c,ce);
2026: cssave(e,retregs | *pretregs,opsflag);
2027: forregs = 0; /* don't care about result in reg */
2028: /* cuz we have real result in rreg */
2029: retregs = *pretregs & ~mPSW;
2030: }
2031: if (forccs) /* if return result in flags */
2032: c = cat(c,tstresult(retregs,tym,forregs));
2033: return c;
2034: }
2035:
2036:
2037: /********************************
2038: * Generate code sequence to call C runtime library support routine.
2039: * clib = CLIBxxxx
2040: * keepmask = mask of registers not to destroy. Currently can
2041: * handle only 1. Should use a temporary rather than
2042: * push/pop for speed.
2043: */
2044:
2045: int clib_inited = 0; // != 0 if initialized
2046:
2047: code *callclib(elem *e,unsigned clib,regm_t *pretregs,regm_t keepmask)
2048: {
2049: //printf("callclib(e = %p, clib = %d, *pretregs = %s, keepmask = %s\n", e, clib, regm_str(*pretregs), regm_str(keepmask));
2050: //elem_print(e);
2051: #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
2052: static symbol lib[] =
2053: {
2054: /* Convert destroyed regs into saved regs */
2055: #define Z(desregs) (~(desregs) & (mBP| mES | ALLREGS))
2056: #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
2057: #define N(name) "_" name
2058: #else
2059: #define N(name) name
2060: #endif
2061:
2062: /* Shorthand to map onto SYMBOLY() */
2063: #define Y(desregs,name) SYMBOLY(FLfunc,Z(desregs),N(name),0)
2064:
2065: Y(0,"_LCMP__"), // CLIBlcmp
2066: Y(mAX|mCX|mDX,"_LMUL__"), // CLIBlmul
2067: #if 1
2068: Y(mAX|mBX|mCX|mDX,"_LDIV__"), // CLIBldiv
2069: Y(mAX|mBX|mCX|mDX,"_LDIV__"), // CLIBlmod
2070: Y(mAX|mBX|mCX|mDX,"_ULDIV__"), // CLIBuldiv
2071: Y(mAX|mBX|mCX|mDX,"_ULDIV__"), // CLIBulmod
2072: #else
2073: Y(ALLREGS,"_LDIV__"), // CLIBldiv
2074: Y(ALLREGS,"_LDIV__"), // CLIBlmod
2075: Y(ALLREGS,"_ULDIV__"), // CLIBuldiv
2076: Y(ALLREGS,"_ULDIV__"), // CLIBulmod
2077: #endif
2078: #if 0
2079: Y(DOUBLEREGS_16,"_DNEG"),
2080: Y(mAX|mBX|mCX|mDX,"_DMUL"), // CLIBdmul
2081: Y(mAX|mBX|mCX|mDX,"_DDIV"), // CLIBddiv
2082: Y(0,"_DTST0"), // CLIBdtst0
2083: Y(0,"_DTST0EXC"), // CLIBdtst0exc
2084: Y(0,"_DCMP"), // CLIBdcmp
2085: Y(0,"_DCMPEXC"), // CLIBdcmpexc
2086:
2087: Y(mAX|mBX|mCX|mDX,"_DADD"), // CLIBdadd
2088: Y(mAX|mBX|mCX|mDX,"_DSUB"), // CLIBdsub
2089:
2090: Y(mAX|mBX|mCX|mDX,"_FMUL"), // CLIBfmul
2091: Y(mAX|mBX|mCX|mDX,"_FDIV"), // CLIBfdiv
2092: Y(0,"_FTST0"), // CLIBftst0
2093: Y(0,"_FTST0EXC"), // CLIBftst0exc
2094: Y(0,"_FCMP"), // CLIBfcmp
2095: Y(0,"_FCMPEXC"), // CLIBfcmpexc
2096: Y(FLOATREGS_32,"_FNEG"), // CLIBfneg
2097: Y(mAX|mBX|mCX|mDX,"_FADD"), // CLIBfadd
2098: Y(mAX|mBX|mCX|mDX,"_FSUB"), // CLIBfsub
2099: #endif
2100: Y(DOUBLEREGS_32,"_DBLLNG"), // CLIBdbllng
2101: Y(DOUBLEREGS_32,"_LNGDBL"), // CLIBlngdbl
2102: Y(DOUBLEREGS_32,"_DBLINT"), // CLIBdblint
2103: Y(DOUBLEREGS_32,"_INTDBL"), // CLIBintdbl
2104: Y(DOUBLEREGS_32,"_DBLUNS"), // CLIBdbluns
2105: Y(DOUBLEREGS_32,"_UNSDBL"), // CLIBunsdbl
2106: Y(mAX|mST0,"_DBLULNG"), // CLIBdblulng
2107: #if 0
2108: {DOUBLEREGS_16,DOUBLEREGS_32,0,INFfloat,1,1}, // _ULNGDBL@ ulngdbl
2109: #endif
2110: Y(DOUBLEREGS_32,"_DBLFLT"), // CLIBdblflt
2111: Y(DOUBLEREGS_32,"_FLTDBL"), // CLIBfltdbl
2112:
2113: Y(DOUBLEREGS_32,"_DBLLLNG"), // CLIBdblllng
2114: Y(DOUBLEREGS_32,"_LLNGDBL"), // CLIBllngdbl
2115: Y(DOUBLEREGS_32,"_DBLULLNG"), // CLIBdblullng
2116: Y(DOUBLEREGS_32,"_ULLNGDBL"), // CLIBullngdbl
2117:
2118: Y(0,"_DTST"), // CLIBdtst
2119: Y(mES|mBX,"_HTOFPTR"), // CLIBvptrfptr
2120: Y(mES|mBX,"_HCTOFPTR"), // CLIBcvptrfptr
2121: Y(0,"_87TOPSW"), // CLIB87topsw
2122: Y(mST0,"_FLTTO87"), // CLIBfltto87
2123: Y(mST0,"_DBLTO87"), // CLIBdblto87
2124: Y(mST0|mAX,"_DBLINT87"), // CLIBdblint87
2125: Y(mST0|mAX|mDX,"_DBLLNG87"), // CLIBdbllng87
2126: Y(0,"_FTST"), // CLIBftst
2127: Y(0,"_FCOMPP"), // CLIBfcompp
2128: Y(0,"_FTEST"), // CLIBftest
2129: Y(0,"_FTEST0"), // CLIBftest0
2130: Y(mST0|mAX|mBX|mCX|mDX,"_FDIVP"), // CLIBfdiv87
2131:
2132: Y(mST0|mST01,"Cmul"), // CLIBcmul
2133: Y(mAX|mCX|mDX|mST0|mST01,"Cdiv"), // CLIBcdiv
2134: Y(mAX|mST0|mST01,"Ccmp"), // CLIBccmp
2135:
2136: Y(mST0,"_U64_LDBL"), // CLIBu64_ldbl
2137: #if ELFOBJ || MACHOBJ
2138: Y(mST0|mAX|mDX,"_LDBLULLNG"), // CLIBld_u64
2139: #else
2140: Y(mST0|mAX|mDX,"__LDBLULLNG"), // CLIBld_u64
2141: #endif
2142: };
2143: #else
2144: static symbol lib[CLIBMAX] =
2145: {
2146: /* Convert destroyed regs into saved regs */
2147: #define Z(desregs) (~(desregs) & (mBP| mES | ALLREGS))
2148:
2149: /* Shorthand to map onto SYMBOLY() */
2150: #define Y(desregs,name) SYMBOLY(FLfunc,Z(desregs),name,0)
2151:
2152: Y(0,"_LCMP@"),
2153: Y(mAX|mCX|mDX,"_LMUL@"),
2154: Y(ALLREGS,"_LDIV@"),
2155: Y(ALLREGS,"_LDIV@"),
2156: Y(ALLREGS,"_ULDIV@"),
2157: Y(ALLREGS,"_ULDIV@"),
2158: Y(mAX|mBX|mCX|mDX,"_DMUL@"),
2159: Y(mAX|mBX|mCX|mDX,"_DDIV@"),
2160: Y(0,"_DTST0@"),
2161: Y(0,"_DTST0EXC@"),
2162: Y(0,"_DCMP@"),
2163: Y(0,"_DCMPEXC@"),
2164:
2165: /* _DNEG@ only really destroys EDX, but then EAX would hold */
2166: /* 2 values, and we can't handle that. */
2167:
2168: /* _DNEG@ only really destroys AX, but then BX,CX,DX would hold */
2169: /* 2 values, and we can't handle that. */
2170:
2171: Y(DOUBLEREGS_16,"_DNEG@"),
2172: Y(mAX|mBX|mCX|mDX,"_DADD@"),
2173: Y(mAX|mBX|mCX|mDX,"_DSUB@"),
2174:
2175: Y(mAX|mBX|mCX|mDX,"_FMUL@"),
2176: Y(mAX|mBX|mCX|mDX,"_FDIV@"),
2177: Y(0,"_FTST0@"),
2178: Y(0,"_FTST0EXC@"),
2179: Y(0,"_FCMP@"),
2180: Y(0,"_FCMPEXC@"),
2181: Y(FLOATREGS_16,"_FNEG@"),
2182: Y(mAX|mBX|mCX|mDX,"_FADD@"),
2183: Y(mAX|mBX|mCX|mDX,"_FSUB@"),
2184: Y(DOUBLEREGS_16,"_DBLLNG@"),
2185: Y(DOUBLEREGS_16,"_LNGDBL@"),
2186: Y(DOUBLEREGS_16,"_DBLINT@"),
2187: Y(DOUBLEREGS_16,"_INTDBL@"),
2188: Y(DOUBLEREGS_16,"_DBLUNS@"),
2189: Y(DOUBLEREGS_16,"_UNSDBL@"),
2190: Y(DOUBLEREGS_16,"_DBLULNG@"),
2191: Y(DOUBLEREGS_16,"_ULNGDBL@"),
2192: Y(DOUBLEREGS_16,"_DBLFLT@"),
2193: Y(ALLREGS,"_FLTDBL@"),
2194:
2195: Y(DOUBLEREGS_16,"_DBLLLNG@"),
2196: Y(DOUBLEREGS_16,"_LLNGDBL@"),
2197: #if 0
2198: Y(DOUBLEREGS_16,"__DBLULLNG"),
2199: #else
2200: Y(DOUBLEREGS_16,"_DBLULLNG@"),
2201: #endif
2202: Y(DOUBLEREGS_16,"_ULLNGDBL@"),
2203:
2204: Y(0,"_DTST@"),
2205: Y(mES|mBX,"_HTOFPTR@"), // CLIBvptrfptr
2206: Y(mES|mBX,"_HCTOFPTR@"), // CLIBcvptrfptr
2207: Y(0,"_87TOPSW@"), // CLIB87topsw
2208: Y(mST0,"_FLTTO87@"), // CLIBfltto87
2209: Y(mST0,"_DBLTO87@"), // CLIBdblto87
2210: Y(mST0|mAX,"_DBLINT87@"), // CLIBdblint87
2211: Y(mST0|mAX|mDX,"_DBLLNG87@"), // CLIBdbllng87
2212: Y(0,"_FTST@"),
2213: Y(0,"_FCOMPP@"), // CLIBfcompp
2214: Y(0,"_FTEST@"), // CLIBftest
2215: Y(0,"_FTEST0@"), // CLIBftest0
2216: Y(mST0|mAX|mBX|mCX|mDX,"_FDIVP"), // CLIBfdiv87
2217:
2218: // NOTE: desregs is wrong for 16 bit code, mBX should be included
2219: Y(mST0|mST01,"_Cmul"), // CLIBcmul
2220: Y(mAX|mCX|mDX|mST0|mST01,"_Cdiv"), // CLIBcdiv
2221: Y(mAX|mST0|mST01,"_Ccmp"), // CLIBccmp
2222:
2223: Y(mST0,"_U64_LDBL"), // CLIBu64_ldbl
2224: Y(mST0|mAX|mDX,"__LDBLULLNG"), // CLIBld_u64
2225: };
2226: #endif
2227:
2228: static struct
2229: {
2230: regm_t retregs16; /* registers that 16 bit result is returned in */
2231: regm_t retregs32; /* registers that 32 bit result is returned in */
2232: char pop; /* # of bytes popped off of stack upon return */
2233: char flags;
2234: #define INF32 1 // if 32 bit only
2235: #define INFfloat 2 // if this is floating point
2236: #define INFwkdone 4 // if weak extern is already done
2237: #define INF64 8 // if 64 bit only
2238: char push87; // # of pushes onto the 8087 stack
2239: char pop87; // # of pops off of the 8087 stack
2240: } info[CLIBMAX] =
2241: {
2242: {0,0,0,0}, /* _LCMP@ lcmp */
2243: {mDX|mAX,mDX|mAX,0,0}, // _LMUL@ lmul
2244: {mDX|mAX,mDX|mAX,0,0}, // _LDIV@ ldiv
2245: {mCX|mBX,mCX|mBX,0,0}, /* _LDIV@ lmod */
2246: {mDX|mAX,mDX|mAX,0,0}, /* _ULDIV@ uldiv */
2247: {mCX|mBX,mCX|mBX,0,0}, /* _ULDIV@ ulmod */
2248:
2249: #if TARGET_WINDOS
2250: {DOUBLEREGS_16,DOUBLEREGS_32,8,INFfloat,1,1}, // _DMUL@ dmul
2251: {DOUBLEREGS_16,DOUBLEREGS_32,8,INFfloat,1,1}, // _DDIV@ ddiv
2252: {0,0,0,2}, // _DTST0@
2253: {0,0,0,2}, // _DTST0EXC@
2254: {0,0,8,INFfloat,1,1}, // _DCMP@ dcmp
2255: {0,0,8,INFfloat,1,1}, // _DCMPEXC@ dcmp
2256: {DOUBLEREGS_16,DOUBLEREGS_32,0,2}, // _DNEG@ dneg
2257: {DOUBLEREGS_16,DOUBLEREGS_32,8,INFfloat,1,1}, // _DADD@ dadd
2258: {DOUBLEREGS_16,DOUBLEREGS_32,8,INFfloat,1,1}, // _DSUB@ dsub
2259:
2260: {FLOATREGS_16,FLOATREGS_32,0,INFfloat,1,1}, // _FMUL@ fmul
2261: {FLOATREGS_16,FLOATREGS_32,0,INFfloat,1,1}, // _FDIV@ fdiv
2262: {0,0,0,2}, // _FTST0@
2263: {0,0,0,2}, // _FTST0EXC@
2264: {0,0,0,INFfloat,1,1}, // _FCMP@ fcmp
2265: {0,0,0,INFfloat,1,1}, // _FCMPEXC@ fcmp
2266: {FLOATREGS_16,FLOATREGS_32,0,2}, // _FNEG@ fneg
2267: {FLOATREGS_16,FLOATREGS_32,0,INFfloat,1,1}, // _FADD@ fadd
2268: {FLOATREGS_16,FLOATREGS_32,0,INFfloat,1,1}, // _FSUB@ fsub
2269: #endif
2270:
2271: {mDX|mAX,mAX,0,INFfloat,1,1}, // _DBLLNG@ dbllng
2272: {DOUBLEREGS_16,DOUBLEREGS_32,0,INFfloat,1,1}, // _LNGDBL@ lngdbl
2273: {mAX,mAX,0,INFfloat,1,1}, // _DBLINT@ dblint
2274: {DOUBLEREGS_16,DOUBLEREGS_32,0,INFfloat,1,1}, // _INTDBL@ intdbl
2275: {mAX,mAX,0,INFfloat,1,1}, // _DBLUNS@ dbluns
2276: {DOUBLEREGS_16,DOUBLEREGS_32,0,INFfloat,1,1}, // _UNSDBL@ unsdbl
2277: #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
2278: {mDX|mAX,mAX,0,INF32|INFfloat,0,1}, // _DBLULNG@ dblulng
2279: #else
2280: {mDX|mAX,mAX,0,INFfloat,1,1}, // _DBLULNG@ dblulng
2281: #endif
2282: #if TARGET_WINDOS
2283: {DOUBLEREGS_16,DOUBLEREGS_32,0,INFfloat,1,1}, // _ULNGDBL@ ulngdbl
2284: #endif
2285: {FLOATREGS_16,FLOATREGS_32,0,INFfloat,1,1}, // _DBLFLT@ dblflt
2286: {DOUBLEREGS_16,DOUBLEREGS_32,0,INFfloat,1,1}, // _FLTDBL@ fltdbl
2287:
2288: {DOUBLEREGS_16,mDX|mAX,0,INFfloat,1,1}, // _DBLLLNG@
2289: {DOUBLEREGS_16,DOUBLEREGS_32,0,INFfloat,1,1}, // _LLNGDBL@
2290: #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
2291: {DOUBLEREGS_16,mDX|mAX,0,INFfloat,2,2}, // _DBLULLNG@
2292: #else
2293: {DOUBLEREGS_16,mDX|mAX,0,INFfloat,1,1}, // _DBLULLNG@
2294: #endif
2295: {DOUBLEREGS_16,DOUBLEREGS_32,0,INFfloat,1,1}, // _ULLNGDBL@
2296:
2297: {0,0,0,2}, // _DTST@ dtst
2298: {mES|mBX,mES|mBX,0,0}, // _HTOFPTR@ vptrfptr
2299: {mES|mBX,mES|mBX,0,0}, // _HCTOFPTR@ cvptrfptr
2300: {0,0,0,2}, // _87TOPSW@ 87topsw
2301: {mST0,mST0,0,INFfloat,1,0}, // _FLTTO87@ fltto87
2302: {mST0,mST0,0,INFfloat,1,0}, // _DBLTO87@ dblto87
2303: {mAX,mAX,0,2}, // _DBLINT87@ dblint87
2304: {mDX|mAX,mAX,0,2}, // _DBLLNG87@ dbllng87
2305: {0,0,0,2}, // _FTST@
2306: {mPSW,mPSW,0,INFfloat,0,2}, // _FCOMPP@
2307: {mPSW,mPSW,0,2}, // _FTEST@
2308: {mPSW,mPSW,0,2}, // _FTEST0@
2309: {mST0,mST0,0,INFfloat,1,1}, // _FDIV@
2310:
2311: {mST01,mST01,0,INF32|INFfloat,3,5}, // _Cmul
2312: {mST01,mST01,0,INF32|INFfloat,0,2}, // _Cdiv
2313: {mPSW, mPSW, 0,INF32|INFfloat,0,4}, // _Ccmp
2314:
2315: {mST0,mST0,0,INF32|INF64|INFfloat,2,1}, // _U64_LDBL
2316: {0,mDX|mAX,0,INF32|INF64|INFfloat,1,2}, // __LDBLULLNG
2317: };
2318:
2319: if (!clib_inited) /* if not initialized */
2320: {
2321: assert(sizeof(lib) / sizeof(lib[0]) == CLIBMAX);
2322: assert(sizeof(info) / sizeof(info[0]) == CLIBMAX);
2323: for (int i = 0; i < CLIBMAX; i++)
2324: { lib[i].Stype = tsclib;
2325: #if MARS
2326: lib[i].Sxtrnnum = 0;
2327: lib[i].Stypidx = 0;
2328: #endif
2329: }
2330:
2331: if (!I16)
2332: { /* Adjust table for 386 */
2333: lib[CLIBdbllng].Sregsaved = Z(DOUBLEREGS_32);
2334: lib[CLIBlngdbl].Sregsaved = Z(DOUBLEREGS_32);
2335: lib[CLIBdblint].Sregsaved = Z(DOUBLEREGS_32);
2336: lib[CLIBintdbl].Sregsaved = Z(DOUBLEREGS_32);
2337: #if TARGET_WINDOS
2338: lib[CLIBfneg].Sregsaved = Z(FLOATREGS_32);
2339: lib[CLIBdneg].Sregsaved = Z(DOUBLEREGS_32);
2340: lib[CLIBdbluns].Sregsaved = Z(DOUBLEREGS_32);
2341: lib[CLIBunsdbl].Sregsaved = Z(DOUBLEREGS_32);
2342: lib[CLIBdblulng].Sregsaved = Z(DOUBLEREGS_32);
2343: lib[CLIBulngdbl].Sregsaved = Z(DOUBLEREGS_32);
2344: #endif
2345: lib[CLIBdblflt].Sregsaved = Z(DOUBLEREGS_32);
2346: lib[CLIBfltdbl].Sregsaved = Z(DOUBLEREGS_32);
2347:
2348: lib[CLIBdblllng].Sregsaved = Z(DOUBLEREGS_32);
2349: lib[CLIBllngdbl].Sregsaved = Z(DOUBLEREGS_32);
2350: lib[CLIBdblullng].Sregsaved = Z(DOUBLEREGS_32);
2351: lib[CLIBullngdbl].Sregsaved = Z(DOUBLEREGS_32);
2352:
2353: if (I64)
2354: {
2355: info[CLIBullngdbl].retregs32 = mAX;
2356: info[CLIBdblullng].retregs32 = mAX;
2357: }
2358: }
2359: clib_inited++;
2360: }
2361: #undef Z
2362:
2363: assert(clib < CLIBMAX);
2364: symbol *s = &lib[clib];
2365: if (I16)
2366: assert(!(info[clib].flags & (INF32 | INF64)));
2367: code *cpop = CNIL;
2368: code *c = getregs((~s->Sregsaved & (mES | mBP | ALLREGS)) & ~keepmask); // mask of regs destroyed
2369: keepmask &= ~s->Sregsaved;
2370: int npushed = numbitsset(keepmask);
2371: gensaverestore2(keepmask, &c, &cpop);
2372: #if 0
2373: while (keepmask)
2374: { unsigned keepreg;
2375:
2376: if (keepmask & (mBP|ALLREGS))
2377: { keepreg = findreg(keepmask & (mBP|ALLREGS));
2378: c = gen1(c,0x50 + keepreg); /* PUSH keepreg */
2379: cpop = cat(gen1(CNIL,0x58 + keepreg),cpop); // POP keepreg
2380: keepmask &= ~mask[keepreg];
2381: npushed++;
2382: }
2383: if (keepmask & mES)
2384: { c = gen1(c,0x06); /* PUSH ES */
2385: cpop = cat(gen1(CNIL,0x07),cpop); /* POP ES */
2386: keepmask &= ~mES;
2387: npushed++;
2388: }
2389: }
2390: #endif
2391:
2392: c = cat(c, save87regs(info[clib].push87));
2393: for (int i = 0; i < info[clib].push87; i++)
2394: c = cat(c, push87());
2395:
2396: for (int i = 0; i < info[clib].pop87; i++)
2397: pop87();
2398:
2399: if (config.target_cpu >= TARGET_80386 && clib == CLIBlmul && !I32)
2400: { static char lmul[] = {
2401: 0x66,0xc1,0xe1,0x10, // shl ECX,16
warning C4309: 'initializing' : truncation of constant value
warning C4309: 'initializing' : truncation of constant value
2402: 0x8b,0xcb, // mov CX,BX ;ECX = CX,BX
warning C4309: 'initializing' : truncation of constant value
warning C4309: 'initializing' : truncation of constant value
2403: 0x66,0xc1,0xe0,0x10, // shl EAX,16
warning C4309: 'initializing' : truncation of constant value
warning C4309: 'initializing' : truncation of constant value
2404: 0x66,0x0f,0xac,0xd0,0x10, // shrd EAX,EDX,16 ;EAX = DX,AX
warning C4309: 'initializing' : truncation of constant value
warning C4309: 'initializing' : truncation of constant value
2405: 0x66,0xf7,0xe1, // mul ECX
warning C4309: 'initializing' : truncation of constant value
warning C4309: 'initializing' : truncation of constant value
2406: 0x66,0x0f,0xa4,0xc2,0x10, // shld EDX,EAX,16 ;DX,AX = EAX
warning C4309: 'initializing' : truncation of constant value
warning C4309: 'initializing' : truncation of constant value
2407: };
2408:
2409: c = genasm(c,lmul,sizeof(lmul));
2410: }
2411: else
2412: { makeitextern(s);
2413: int nalign = 0;
2414: if (STACKALIGN == 16)
2415: { // Align the stack (assume no args on stack)
2416: int npush = npushed * REGSIZE + stackpush;
2417: if (npush & (STACKALIGN - 1))
2418: { nalign = STACKALIGN - (npush & (STACKALIGN - 1));
2419: c = genc2(c,0x81,modregrm(3,5,SP),nalign); // SUB ESP,nalign
2420: if (I64)
2421: code_orrex(c, REX_W);
2422: }
2423: }
2424: c = gencs(c,(LARGECODE) ? 0x9A : 0xE8,0,FLfunc,s); // CALL s
2425: if (nalign)
2426: { c = genc2(c,0x81,modregrm(3,0,SP),nalign); // ADD ESP,nalign
2427: if (I64)
2428: code_orrex(c, REX_W);
2429: }
2430: calledafunc = 1;
2431:
2432: if (I16 && // bug in Optlink for weak references
2433: config.flags3 & CFG3wkfloat &&
2434: (info[clib].flags & (INFfloat | INFwkdone)) == INFfloat)
2435: { info[clib].flags |= INFwkdone;
2436: makeitextern(rtlsym[RTLSYM_INTONLY]);
2437: obj_wkext(s,rtlsym[RTLSYM_INTONLY]);
2438: }
2439: }
2440: if (I16)
2441: stackpush -= info[clib].pop;
2442: regm_t retregs = I16 ? info[clib].retregs16 : info[clib].retregs32;
2443: return cat(cat(c,cpop),fixresult(e,retregs,pretregs));
2444: }
2445:
2446: /*************************************************
2447: * Helper function for converting OPparam's into array of Parameters.
2448: */
2449: struct Parameter { elem *e; int reg; unsigned numalign; };
2450:
2451: void fillParameters(elem *e, Parameter *parameters, int *pi)
2452: {
2453: if (e->Eoper == OPparam)
2454: {
2455: fillParameters(e->E1, parameters, pi);
2456: fillParameters(e->E2, parameters, pi);
2457: freenode(e);
2458: }
2459: else
2460: {
2461: parameters[*pi].e = e;
2462: (*pi)++;
2463: }
2464: }
2465:
2466:
2467: /*******************************
2468: * Generate code sequence for function call.
2469: */
2470:
2471: code *cdfunc(elem *e,regm_t *pretregs)
2472: { unsigned numpara = 0;
2473: unsigned stackpushsave;
2474: unsigned preg;
2475: regm_t keepmsk;
2476: unsigned numalign = 0;
2477: code *c;
2478:
2479: //printf("cdfunc()\n"); elem_print(e);
2480: assert(e);
2481: stackpushsave = stackpush; /* so we can compute # of parameters */
2482: cgstate.stackclean++;
2483: c = CNIL;
2484: keepmsk = 0;
2485: if (OTbinary(e->Eoper)) // if parameters
2486: {
2487: if (I16)
2488: {
2489: c = cat(c, params(e->E2,2)); // push parameters
2490: }
2491: else if (I32)
2492: {
2493: unsigned stackalign = REGSIZE;
2494: tym_t tyf = tybasic(e->E1->Ety);
2495:
2496: // First compute numpara, the total bytes pushed on the stack
2497: switch (tyf)
2498: { case TYf16func:
2499: stackalign = 2;
2500: goto Ldefault;
2501: case TYmfunc:
2502: case TYjfunc:
2503: // last parameter goes into register
2504: elem *ep;
2505: for (ep = e->E2; ep->Eoper == OPparam; ep = ep->E2)
2506: {
2507: numpara += paramsize(ep->E1,stackalign);
2508: }
2509: unsigned sz;
2510: if (tyf == TYjfunc &&
2511: // This must match type_jparam()
2512: !(tyjparam(ep->Ety) ||
2513: ((tybasic(ep->Ety) == TYstruct || tybasic(ep->Ety) == TYarray) &&
2514: (sz = type_size(ep->ET)) <= intsize && sz != 3 && sz)
warning C4018: '<=' : signed/unsigned mismatch
2515: )
2516: )
2517: {
2518: numpara += paramsize(ep,stackalign);
2519: }
2520: break;
2521: default:
2522: Ldefault:
2523: numpara += paramsize(e->E2,stackalign);
2524: break;
2525: }
2526: assert((numpara & (REGSIZE - 1)) == 0);
2527: assert((stackpush & (REGSIZE - 1)) == 0);
2528:
2529: /* Special handling for call to __tls_get_addr, we must save registers
2530: * before evaluating the parameter, so that the parameter load and call
2531: * are adjacent.
2532: */
2533: if (e->E2->Eoper != OPparam && e->E1->Eoper == OPvar)
2534: { symbol *s = e->E1->EV.sp.Vsym;
2535: if (s == tls_get_addr_sym)
2536: c = getregs(~s->Sregsaved & (mBP | ALLREGS | mES | XMMREGS));
2537: }
2538:
2539:
2540: /* Adjust start of the stack so after all args are pushed,
2541: * the stack will be aligned.
2542: */
2543: if (STACKALIGN == 16 && (numpara + stackpush) & (STACKALIGN - 1))
2544: {
2545: numalign = STACKALIGN - ((numpara + stackpush) & (STACKALIGN - 1));
2546: c = genc2(c,0x81,modregrm(3,5,SP),numalign); // SUB ESP,numalign
2547: if (I64)
2548: code_orrex(c, REX_W);
2549: c = genadjesp(c, numalign);
2550: stackpush += numalign;
2551: stackpushsave += numalign;
2552: }
2553:
2554: switch (tyf)
2555: { case TYf16func:
2556: stackalign = 2;
2557: goto Ldefault2;
2558: case TYmfunc: // last parameter goes into ECX
2559: preg = CX;
2560: goto L1;
2561: case TYjfunc: // last parameter goes into EAX
2562: preg = AX;
2563: goto L1;
2564: L1:
2565: { elem *ep;
2566: elem *en;
2567: for (ep = e->E2; ep->Eoper == OPparam; ep = en)
2568: {
2569: c = cat(c,params(ep->E1,stackalign));
2570: en = ep->E2;
2571: freenode(ep);
2572: }
2573: unsigned sz;
2574: if (tyf == TYjfunc &&
2575: // This must match type_jparam()
2576: !(tyjparam(ep->Ety) ||
2577: ((tybasic(ep->Ety) == TYstruct || tybasic(ep->Ety) == TYarray) &&
2578: (sz = type_size(ep->ET)) <= intsize && sz != 3 && sz)
warning C4018: '<=' : signed/unsigned mismatch
2579: )
2580: )
2581: {
2582: c = cat(c,params(ep,stackalign));
2583: goto Lret;
2584: }
2585: // preg is the register to put the parameter ep in
2586: keepmsk = mask[preg]; // don't change preg when evaluating func address
2587: regm_t retregs = keepmsk;
2588: if (ep->Eoper == OPstrthis)
2589: { code *c2;
2590:
2591: code *c1 = getregs(retregs);
2592: // LEA preg,np[ESP]
2593: unsigned np = stackpush - ep->EV.Vuns; // stack delta to parameter
2594: c2 = genc1(CNIL,0x8D,(modregrm(0,4,SP) << 8) | modregrm(2,preg,4),FLconst,np);
2595: if (I64)
2596: code_orrex(c2, REX_W);
2597: c = cat3(c,c1,c2);
2598: }
2599: else
2600: { code *cp = codelem(ep,&retregs,FALSE);
2601: c = cat(c,cp);
2602: }
2603: goto Lret;
2604: }
2605: default:
2606: Ldefault2:
2607: c = cat(c, params(e->E2,stackalign)); // push parameters
2608: break;
2609: }
2610: }
2611: else
2612: { assert(I64);
2613:
2614: // Easier to deal with parameters as an array: parameters[0..np]
2615: int np = el_nparams(e->E2);
2616: Parameter *parameters = (Parameter *)alloca(np * sizeof(Parameter));
warning C6255: _alloca indicates failure by raising a stack overflow exception. Consider using _malloca instead
2617:
2618: { int n = 0;
2619: fillParameters(e->E2, parameters, &n);
2620: assert(n == np);
2621: }
2622:
2623: /* Special handling for call to __tls_get_addr, we must save registers
2624: * before evaluating the parameter, so that the parameter load and call
2625: * are adjacent.
2626: */
2627: if (np == 1 && e->E1->Eoper == OPvar)
2628: { symbol *s = e->E1->EV.sp.Vsym;
2629: if (s == tls_get_addr_sym)
2630: c = getregs(~s->Sregsaved & (mBP | ALLREGS | mES | XMMREGS));
2631: }
2632:
2633: unsigned stackalign = REGSIZE;
2634:
2635: // Figure out which parameters go in registers
2636: // Compute numpara, the total bytes pushed on the stack
2637: int r = 0;
2638: int xmmcnt = XMM0;
2639: for (int i = np; --i >= 0;)
2640: {
2641: static const unsigned char argregs[6] = { DI,SI,DX,CX,R8,R9 };
2642: elem *ep = parameters[i].e;
2643: tym_t ty = ep->Ety;
2644: if (r < sizeof(argregs)/sizeof(argregs[0])) // if more arg regs
2645: { unsigned sz;
2646: if (
2647: // This must match type_jparam()
2648: ty64reg(ty) ||
2649: ((tybasic(ty) == TYstruct || tybasic(ty) == TYarray) &&
2650: ((sz = type_size(ep->ET)) == 1 || sz == 2 || sz == 4 || sz == 8))
2651: )
2652: {
2653: parameters[i].reg = argregs[r];
2654: r++;
2655: continue; // goes in register, not stack
2656: }
2657: }
2658: if (xmmcnt <= XMM7)
2659: {
2660: if (tyfloating(ty) && tysize(ty) <= 8 && !tycomplex(ty))
2661: {
2662: parameters[i].reg = xmmcnt;
2663: xmmcnt++;
2664: continue; // goes in register, not stack
2665: }
2666: }
2667:
2668: // Parameter i goes on the stack
2669: parameters[i].reg = -1; // -1 means no register
2670: unsigned alignsize = el_alignsize(ep);
2671: parameters[i].numalign = 0;
2672: if (alignsize > stackalign)
2673: { unsigned newnumpara = (numpara + (alignsize - 1)) & ~(alignsize - 1);
2674: parameters[i].numalign = newnumpara - numpara;
2675: numpara = newnumpara;
2676: }
2677: numpara += paramsize(ep,stackalign);
2678: }
2679:
2680: assert((numpara & (REGSIZE - 1)) == 0);
2681: assert((stackpush & (REGSIZE - 1)) == 0);
2682:
2683: /* Should consider reordering the order of evaluation of the parameters
2684: * so that args that go into registers are evaluated after args that get
2685: * pushed. We can reorder args that are constants or relconst's.
2686: */
2687:
2688: /* Adjust start of the stack so after all args are pushed,
2689: * the stack will be aligned.
2690: */
2691: if (STACKALIGN == 16 && (numpara + stackpush) & (STACKALIGN - 1))
2692: {
2693: numalign = STACKALIGN - ((numpara + stackpush) & (STACKALIGN - 1));
2694: c = genc2(c,0x81,(REX_W << 16) | modregrm(3,5,SP),numalign); // SUB RSP,numalign
2695: c = genadjesp(c, numalign);
2696: stackpush += numalign;
2697: stackpushsave += numalign;
2698: }
2699:
2700: int regsaved[XMM7 + 1];
2701: memset(regsaved, -1, sizeof(regsaved));
2702: code *crest = NULL;
2703: regm_t saved = 0;
2704:
2705: /* Parameters go into the registers RDI,RSI,RDX,RCX,R8,R9
2706: * float and double parameters go into XMM0..XMM7
2707: * For variadic functions, count of XMM registers used goes in AL
2708: */
2709: for (int i = 0; i < np; i++)
2710: {
2711: elem *ep = parameters[i].e;
2712: int preg = parameters[i].reg;
warning C6246: Local declaration of 'preg' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '2474' of 'c:\projects\extern\d\dmd\src\backend\cod1.c': Lines: 2474
2713: if (preg == -1)
2714: {
2715: /* Push parameter on stack, but keep track of registers used
2716: * in the process. If they interfere with keepmsk, we'll have
2717: * to save/restore them.
2718: */
2719: code *csave = NULL;
2720: regm_t overlap = msavereg & keepmsk;
2721: msavereg |= keepmsk;
2722: code *cp = params(ep,stackalign);
2723: regm_t tosave = keepmsk & ~msavereg;
2724: msavereg &= ~keepmsk | overlap;
2725:
2726: // tosave is the mask to save and restore
2727: for (int j = 0; tosave; j++)
2728: { regm_t mi = mask[j];
2729: assert(j <= XMM7);
2730: if (mi & tosave)
2731: {
2732: unsigned idx;
2733: csave = regsave.save(csave, j, &idx);
2734: crest = regsave.restore(crest, j, idx);
2735: saved |= mi;
2736: keepmsk &= ~mi; // don't need to keep these for rest of params
2737: tosave &= ~mi;
2738: }
2739: }
2740:
2741: c = cat4(c, csave, cp, NULL);
2742:
2743: // Alignment for parameter comes after it got pushed
2744: unsigned numalign = parameters[i].numalign;
warning C6246: Local declaration of 'numalign' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '2476' of 'c:\projects\extern\d\dmd\src\backend\cod1.c': Lines: 2476
2745: if (numalign)
2746: {
2747: c = genc2(c,0x81,(REX_W << 16) | modregrm(3,5,SP),numalign); // SUB RSP,numalign
2748: c = genadjesp(c, numalign);
2749: stackpush += numalign;
2750: }
2751: }
2752: else
2753: {
2754: // Goes in register preg, not stack
2755: regm_t retregs = mask[preg];
2756: if (ep->Eoper == OPstrthis)
2757: {
2758: code *c1 = getregs(retregs);
2759: // LEA preg,np[RSP]
2760: unsigned np = stackpush - ep->EV.Vuns; // stack delta to parameter
warning C6246: Local declaration of 'np' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '2615' of 'c:\projects\extern\d\dmd\src\backend\cod1.c': Lines: 2615
2761: code *c2 = genc1(CNIL,0x8D,(REX_W << 16) |
2762: (modregrm(0,4,SP) << 8) |
2763: modregxrm(2,preg,4), FLconst,np);
2764: c = cat3(c,c1,c2);
2765: }
2766: else
2767: { code *cp = scodelem(ep,&retregs,keepmsk,FALSE);
2768: c = cat(c,cp);
2769: }
2770: keepmsk |= retregs; // don't change preg when evaluating func address
2771: }
2772: }
2773:
2774: // Restore any register parameters we saved
2775: c = cat4(c, getregs(saved), crest, NULL);
2776: keepmsk |= saved;
2777:
2778: // Variadic functions store the number of XMM registers used in AL
2779: if (e->Eflags & EFLAGS_variadic)
2780: { code *c1 = getregs(mAX);
2781: c1 = movregconst(c1,AX,xmmcnt - XMM0,1);
2782: c = cat(c, c1);
2783: keepmsk |= mAX;
2784: }
2785: }
2786: }
2787: else
2788: {
2789: /* Adjust start of the stack so
2790: * the stack will be aligned.
2791: */
2792: if (STACKALIGN == 16 && (stackpush) & (STACKALIGN - 1))
2793: {
2794: numalign = STACKALIGN - ((stackpush) & (STACKALIGN - 1));
2795: c = genc2(NULL,0x81,modregrm(3,5,SP),numalign); // SUB ESP,numalign
2796: if (I64)
2797: code_orrex(c, REX_W);
2798: c = genadjesp(c, numalign);
2799: stackpush += numalign;
2800: stackpushsave += numalign;
2801: }
2802:
2803: }
2804: Lret:
2805: cgstate.stackclean--;
2806: if (I16)
2807: numpara = stackpush - stackpushsave;
2808: else
2809: {
2810: if (numpara != stackpush - stackpushsave)
2811: printf("numpara = %d, stackpush = %d, stackpushsave = %d\n", numpara, stackpush, stackpushsave);
2812: assert(numpara == stackpush - stackpushsave);
2813: }
2814: return cat(c,funccall(e,numpara,numalign,pretregs,keepmsk));
2815: }
2816:
2817: /***********************************
2818: */
2819:
2820: code *cdstrthis(elem *e,regm_t *pretregs)
2821: {
2822: code *c1;
2823: code *c2;
2824:
2825: assert(tysize(e->Ety) == REGSIZE);
2826: unsigned reg = findreg(*pretregs & allregs);
2827: c1 = getregs(mask[reg]);
2828: // LEA reg,np[ESP]
2829: unsigned np = stackpush - e->EV.Vuns; // stack delta to parameter
2830: c2 = genc1(CNIL,0x8D,(modregrm(0,4,SP) << 8) | modregxrm(2,reg,4),FLconst,np);
2831: if (I64)
2832: code_orrex(c2, REX_W);
2833: return cat3(c1,c2,fixresult(e,mask[reg],pretregs));
2834: }
2835:
2836: /******************************
2837: * Call function. All parameters are pushed onto the stack, numpara gives
2838: * the size of them all.
2839: */
2840:
2841: STATIC code * funccall(elem *e,unsigned numpara,unsigned numalign,regm_t *pretregs,regm_t keepmsk)
2842: {
2843: elem *e1;
2844: code *c,*ce,cs;
2845: tym_t tym1;
2846: char farfunc;
2847: regm_t retregs;
2848: symbol *s;
2849:
2850: //printf("funccall(e = %p, *pretregs = x%x, numpara = %d, numalign = %d)\n",e,*pretregs,numpara,numalign);
2851: calledafunc = 1;
2852: /* Determine if we need frame for function prolog/epilog */
2853: #if TARGET_WINDOS
2854: if (config.memmodel == Vmodel)
2855: {
2856: if (tyfarfunc(funcsym_p->ty()))
2857: needframe = TRUE;
2858: }
2859: #endif
2860: e1 = e->E1;
2861: tym1 = tybasic(e1->Ety);
2862: farfunc = tyfarfunc(tym1) || tym1 == TYifunc;
2863: c = NULL;
2864: if (e1->Eoper == OPvar)
2865: { /* Call function directly */
2866: code *c1;
2867:
2868: #ifdef DEBUG
2869: if (!tyfunc(tym1)) WRTYxx(tym1);
2870: #endif
2871: assert(tyfunc(tym1));
2872: s = e1->EV.sp.Vsym;
2873: if (s->Sflags & SFLexit)
2874: c = NULL;
2875: else if (s != tls_get_addr_sym)
2876: c = save87(); // assume 8087 regs are all trashed
2877: if (s->Sflags & SFLexit)
2878: // Function doesn't return, so don't worry about registers
2879: // it may use
2880: c1 = NULL;
2881: else if (!tyfunc(s->ty()) || !(config.flags4 & CFG4optimized))
2882: // so we can replace func at runtime
2883: c1 = getregs(~fregsaved & (mBP | ALLREGS | mES | XMMREGS));
2884: else
2885: c1 = getregs(~s->Sregsaved & (mBP | ALLREGS | mES | XMMREGS));
2886: if (strcmp(s->Sident,"alloca") == 0)
2887: {
2888: #if 1
2889: s = rtlsym[RTLSYM_ALLOCA];
2890: makeitextern(s);
2891: c1 = cat(c1,getregs(mCX));
2892: c1 = genc(c1,0x8D,modregrm(2,CX,BPRM),FLallocatmp,0,0,0); // LEA CX,&localsize[BP]
2893: if (I64)
2894: code_orrex(c1, REX_W);
2895: usedalloca = 2; // new way
2896: #else
2897: usedalloca = 1; // old way
2898: #endif
2899: }
2900: if (sytab[s->Sclass] & SCSS) // if function is on stack (!)
2901: {
2902: retregs = allregs & ~keepmsk;
2903: s->Sflags &= ~GTregcand;
2904: s->Sflags |= SFLread;
2905: ce = cat(c1,cdrelconst(e1,&retregs));
2906: if (farfunc)
2907: goto LF1;
2908: else
2909: goto LF2;
2910: }
2911: else
2912: { int fl;
2913:
2914: fl = FLfunc;
2915: if (!tyfunc(s->ty()))
2916: fl = el_fl(e1);
2917: if (tym1 == TYifunc)
2918: c1 = gen1(c1,0x9C); // PUSHF
2919: #if 0 && TARGET_LINUX
2920: if (s->Sfl == FLgot || s->Sfl == FLgotoff)
2921: fl = s->Sfl;
2922: #endif
2923: ce = gencs(CNIL,farfunc ? 0x9A : 0xE8,0,fl,s); // CALL extern
2924: ce->Iflags |= farfunc ? (CFseg | CFoff) : (CFselfrel | CFoff);
2925: #if TARGET_LINUX
2926: if (s == tls_get_addr_sym)
2927: {
2928: if (I32)
2929: {
2930: /* Append a NOP so GNU linker has patch room
2931: */
2932: ce = gen1(ce, 0x90); // NOP
2933: code_orflag(ce, CFvolatile); // don't schedule it
2934: }
2935: else
2936: { /* Prepend 66 66 48 so GNU linker has patch room
2937: */
2938: assert(I64);
2939: ce->Irex = REX | REX_W;
2940: ce = cat(gen1(CNIL, 0x66), ce);
2941: ce = cat(gen1(CNIL, 0x66), ce);
2942: }
2943: }
2944: #endif
2945: }
2946: ce = cat(c1,ce);
2947: }
2948: else
2949: { /* Call function via pointer */
2950: elem *e11;
2951: tym_t e11ty;
2952:
2953: #ifdef DEBUG
2954: if (e1->Eoper != OPind
2955: ) { WRFL((enum FL)el_fl(e1)); WROP(e1->Eoper); }
2956: #endif
2957: c = save87(); // assume 8087 regs are all trashed
2958: assert(e1->Eoper == OPind);
2959: e11 = e1->E1;
2960: e11ty = tybasic(e11->Ety);
2961: assert(!I16 || (e11ty == (farfunc ? TYfptr : TYnptr)));
2962:
2963: /* if we can't use loadea() */
2964: if ((EOP(e11) || e11->Eoper == OPconst) &&
2965: (e11->Eoper != OPind || e11->Ecount))
2966: {
2967: unsigned reg;
2968:
2969: retregs = allregs & ~keepmsk;
2970: cgstate.stackclean++;
2971: ce = scodelem(e11,&retregs,keepmsk,TRUE);
2972: cgstate.stackclean--;
2973: /* Kill registers destroyed by an arbitrary function call */
2974: ce = cat(ce,getregs((mBP | ALLREGS | mES | XMMREGS) & ~fregsaved));
2975: if (e11ty == TYfptr)
2976: { unsigned lsreg;
2977: LF1:
2978: reg = findregmsw(retregs);
2979: lsreg = findreglsw(retregs);
2980: floatreg = TRUE; /* use float register */
2981: reflocal = TRUE;
2982: ce = genc1(ce,0x89, /* MOV floatreg+2,reg */
2983: modregrm(2,reg,BPRM),FLfltreg,REGSIZE);
2984: genc1(ce,0x89, /* MOV floatreg,lsreg */
2985: modregrm(2,lsreg,BPRM),FLfltreg,0);
2986: if (tym1 == TYifunc)
2987: gen1(ce,0x9C); // PUSHF
2988: genc1(ce,0xFF, /* CALL [floatreg] */
2989: modregrm(2,3,BPRM),FLfltreg,0);
2990: }
2991: else
2992: {
2993: LF2:
2994: reg = findreg(retregs);
2995: ce = gen2(ce,0xFF,modregrmx(3,2,reg)); /* CALL reg */
2996: if (I64)
2997: code_orrex(ce, REX_W);
2998: }
2999: }
3000: else
3001: {
3002: if (tym1 == TYifunc)
3003: c = gen1(c,0x9C); // PUSHF
3004: // CALL [function]
3005: cs.Iflags = 0;
3006: cgstate.stackclean++;
3007: ce = loadea(e11,&cs,0xFF,farfunc ? 3 : 2,0,keepmsk,(mBP|ALLREGS|mES|XMMREGS) & ~fregsaved);
3008: cgstate.stackclean--;
3009: freenode(e11);
3010: }
3011: s = NULL;
3012: }
3013: c = cat(c,ce);
3014: freenode(e1);
3015:
3016: /* See if we will need the frame pointer.
3017: Calculate it here so we can possibly use BP to fix the stack.
3018: */
3019: #if 0
3020: if (!needframe)
3021: { SYMIDX si;
3022:
3023: /* If there is a register available for this basic block */
3024: if (config.flags4 & CFG4optimized && (ALLREGS & ~regcon.used))
3025: ;
3026: else
3027: {
3028: for (si = 0; si < globsym.top; si++)
3029: { symbol *s = globsym.tab[si];
3030:
3031: if (s->Sflags & GTregcand && type_size(s->Stype) != 0)
3032: {
3033: if (config.flags4 & CFG4optimized)
3034: { /* If symbol is live in this basic block and */
3035: /* isn't already in a register */
3036: if (s->Srange && vec_testbit(dfoidx,s->Srange) &&
3037: s->Sfl != FLreg)
3038: { /* Then symbol must be allocated on stack */
3039: needframe = TRUE;
3040: break;
3041: }
3042: }
3043: else
3044: { if (mfuncreg == 0) /* if no registers left */
3045: { needframe = TRUE;
3046: break;
3047: }
3048: }
3049: }
3050: }
3051: }
3052: }
3053: #endif
3054:
3055: retregs = regmask(e->Ety, tym1);
3056:
3057: // If stack needs cleanup
3058: if (OTbinary(e->Eoper) &&
3059: !typfunc(tym1) &&
3060: !(s && s->Sflags & SFLexit))
3061: {
3062: if (tym1 == TYhfunc)
3063: { // Hidden parameter is popped off by the callee
3064: c = genadjesp(c, -REGSIZE);
3065: stackpush -= REGSIZE;
3066: if (numpara + numalign > REGSIZE)
warning C4018: '>' : signed/unsigned mismatch
3067: c = genstackclean(c, numpara + numalign - REGSIZE, retregs);
3068: }
3069: else
3070: c = genstackclean(c,numpara + numalign,retregs);
3071: }
3072: else
3073: {
3074: c = genadjesp(c,-numpara);
warning C4146: unary minus operator applied to unsigned type, result still unsigned
3075: stackpush -= numpara;
3076: if (numalign)
3077: c = genstackclean(c,numalign,retregs);
3078: }
3079:
3080: /* Special handling for functions which return a floating point
3081: value in the top of the 8087 stack.
3082: */
3083:
3084: if (retregs & mST0)
3085: {
3086: if (*pretregs) // if we want the result
3087: { //assert(stackused == 0);
3088: push87(); // one item on 8087 stack
3089: return cat(c,fixresult87(e,retregs,pretregs));
3090: }
3091: else
3092: /* Pop unused result off 8087 stack */
3093: c = gen2(c,0xDD,modregrm(3,3,0)); /* FPOP */
3094: }
3095: else if (retregs & mST01)
3096: {
3097: if (*pretregs) // if we want the result
3098: { assert(stackused == 0);
3099: push87();
3100: push87(); // two items on 8087 stack
3101: return cat(c,fixresult_complex87(e,retregs,pretregs));
3102: }
3103: else
3104: {
3105: // Pop unused result off 8087 stack
3106: c = gen2(c,0xDD,modregrm(3,3,0)); // FPOP
3107: c = gen2(c,0xDD,modregrm(3,3,0)); // FPOP
3108: }
3109: }
3110:
3111: return cat(c,fixresult(e,retregs,pretregs));
3112: }
3113:
3114: /***************************
3115: * Determine size of everything that will be pushed.
3116: */
3117:
3118: targ_size_t paramsize(elem *e,unsigned stackalign)
3119: {
3120: targ_size_t psize = 0;
3121: targ_size_t szb;
3122:
3123: while (e->Eoper == OPparam) /* if more params */
3124: {
3125: elem *e2 = e->E2;
3126: psize += paramsize(e->E1,stackalign); // push them backwards
3127: e = e2;
3128: }
3129: tym_t tym = tybasic(e->Ety);
3130: if (tyscalar(tym))
3131: szb = size(tym);
3132: else if (tym == TYstruct)
3133: szb = type_size(e->ET);
3134: else
3135: {
3136: #ifdef DEBUG
3137: WRTYxx(tym);
3138: #endif
3139: assert(0);
3140: }
3141: psize += align(stackalign,szb); /* align on word stack boundary */
3142: return psize;
3143: }
3144:
3145: /***************************
3146: * Generate code to push parameter list.
3147: * stackpush is incremented by stackalign for each PUSH.
3148: */
3149:
3150: code *params(elem *e,unsigned stackalign)
3151: { code *c,*ce,cs;
3152: code *cp;
3153: unsigned reg;
3154: targ_size_t szb; // size before alignment
3155: targ_size_t sz; // size after alignment
3156: tym_t tym;
3157: regm_t retregs;
3158: elem *e1;
3159: elem *e2;
3160: symbol *s;
warning C4101: 's' : unreferenced local variable
3161: int fl;
warning C4101: 'fl' : unreferenced local variable
3162:
3163: //printf("params(e = %p, stackalign = %d)\n", e, stackalign);
3164: cp = NULL;
3165: stackchanged = 1;
3166: assert(e);
3167: while (e->Eoper == OPparam) /* if more params */
3168: {
3169: e2 = e->E2;
3170: cp = cat(cp,params(e->E1,stackalign)); // push them backwards
3171: freenode(e);
3172: e = e2;
3173: }
3174: //printf("params()\n"); elem_print(e);
3175:
3176: tym = tybasic(e->Ety);
3177: if (tyfloating(tym))
3178: obj_fltused();
3179:
3180: int grex = I64 ? REX_W << 16 : 0;
3181:
3182: /* sz = number of bytes pushed */
3183: if (tyscalar(tym))
3184: szb = size(tym);
3185: else if (tym == TYstruct)
3186: szb = type_size(e->ET);
3187: else
3188: {
3189: #ifdef DEBUG
3190: WRTYxx(tym);
3191: #endif
3192: assert(0);
3193: }
3194: sz = align(stackalign,szb); /* align on word stack boundary */
3195: assert((sz & (stackalign - 1)) == 0); /* ensure that alignment worked */
3196: assert((sz & (REGSIZE - 1)) == 0);
3197:
3198: c = CNIL;
3199: cs.Iflags = 0;
3200: cs.Irex = 0;
3201: switch (e->Eoper)
3202: {
3203: #if SCPP
3204: case OPstrctor:
3205: {
3206: e1 = e->E1;
3207: c = docommas(&e1); /* skip over any comma expressions */
3208:
3209: c = genc2(c,0x81,grex | modregrm(3,5,SP),sz); // SUB SP,sizeof(struct)
3210: stackpush += sz;
3211: genadjesp(c,sz);
3212:
3213: // Find OPstrthis and set it to stackpush
3214: exp2_setstrthis(e1,NULL,stackpush,NULL);
3215:
3216: retregs = 0;
3217: ce = codelem(e1,&retregs,TRUE);
3218: goto L2;
3219: }
3220: case OPstrthis:
3221: // This is the parameter for the 'this' pointer corresponding to
3222: // OPstrctor. We push a pointer to an object that was already
3223: // allocated on the stack by OPstrctor.
3224: { unsigned np;
3225:
3226: retregs = allregs;
3227: c = allocreg(&retregs,®,TYoffset);
3228: c = genregs(c,0x89,SP,reg); // MOV reg,SP
3229: if (I64)
3230: code_orrex(c, REX_W);
3231: np = stackpush - e->EV.Vuns; // stack delta to parameter
3232: c = genc2(c,0x81,grex | modregrmx(3,0,reg),np); // ADD reg,np
3233: if (sz > REGSIZE)
3234: { c = gen1(c,0x16); // PUSH SS
3235: stackpush += REGSIZE;
3236: }
3237: c = gen1(c,0x50 + (reg & 7)); // PUSH reg
3238: if (reg & 8)
3239: code_orrex(c, REX_B);
3240: stackpush += REGSIZE;
3241: genadjesp(c,sz);
3242: ce = CNIL;
3243: goto L2;
3244: }
3245: #endif
3246: case OPstrpar:
3247: { code *cc,*c1,*c2,*c3;
3248: unsigned rm;
3249: unsigned seg; // segment override prefix flags
3250: bool doneoff;
3251: unsigned pushsize = REGSIZE;
3252: unsigned op16 = 0;
3253: unsigned npushes;
3254:
3255: e1 = e->E1;
3256: if (sz == 0)
3257: {
3258: ce = docommas(&e1); /* skip over any commas */
3259: goto L2;
3260: }
3261: if ((sz & 3) == 0 && (sz / REGSIZE) <= 4 && e1->Eoper == OPvar)
3262: { freenode(e);
3263: e = e1;
3264: goto L1;
3265: }
3266: cc = docommas(&e1); /* skip over any commas */
3267: seg = 0; /* assume no seg override */
3268: retregs = sz ? IDXREGS : 0;
3269: doneoff = FALSE;
3270: if (!I16 && sz & 2) // if odd number of words to push
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
3271: { pushsize = 2;
3272: op16 = 1;
3273: }
3274: else if (I16 && config.target_cpu >= TARGET_80386 && (sz & 3) == 0)
3275: { pushsize = 4; // push DWORDs at a time
3276: op16 = 1;
3277: }
3278: npushes = sz / pushsize;
3279: switch (e1->Eoper)
3280: { case OPind:
3281: if (sz)
3282: { switch (tybasic(e1->E1->Ety))
3283: {
3284: case TYfptr:
3285: case TYhptr:
3286: seg = CFes;
3287: retregs |= mES;
3288: break;
3289: case TYsptr:
3290: if (config.wflags & WFssneds)
3291: seg = CFss;
3292: break;
3293: case TYcptr:
3294: seg = CFcs;
3295: break;
3296: }
3297: }
3298: c1 = codelem(e1->E1,&retregs,FALSE);
3299: freenode(e1);
3300: break;
3301: case OPvar:
3302: /* Symbol is no longer a candidate for a register */
3303: e1->EV.sp.Vsym->Sflags &= ~GTregcand;
3304:
3305: if (!e1->Ecount && npushes > 4)
3306: { /* Kludge to point at last word in struct. */
3307: /* Don't screw up CSEs. */
3308: e1->EV.sp.Voffset += sz - pushsize;
3309: doneoff = TRUE;
3310: }
3311: //if (LARGEDATA) /* if default isn't DS */
3312: { static unsigned segtocf[4] = { CFes,CFcs,CFss,0 };
3313: unsigned s;
warning C6246: Local declaration of 's' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '3160' of 'c:\projects\extern\d\dmd\src\backend\cod1.c': Lines: 3160
3314: int fl;
warning C6246: Local declaration of 'fl' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '3161' of 'c:\projects\extern\d\dmd\src\backend\cod1.c': Lines: 3161
3315:
3316: fl = el_fl(e1);
3317: if (fl == FLfardata)
3318: { seg = CFes;
3319: assert(!TARGET_FLAT);
3320: retregs |= mES;
3321: }
3322: else
3323: {
3324: s = segfl[fl];
3325: assert(s < 4);
3326: seg = segtocf[s];
3327: if (seg == CFss && !(config.wflags & WFssneds))
3328: seg = 0;
3329: }
3330: }
3331: #if !TARGET_FLAT
3332: if (e1->Ety & mTYfar)
3333: { seg = CFes;
3334: retregs |= mES;
3335: }
3336: #endif
3337: c1 = cdrelconst(e1,&retregs);
3338: /* Reverse the effect of the previous add */
3339: if (doneoff)
3340: e1->EV.sp.Voffset -= sz - pushsize;
3341: freenode(e1);
3342: break;
3343: case OPstreq:
3344: //case OPcond:
3345: if (!(config.exe & EX_flat))
3346: { seg = CFes;
3347: retregs |= mES;
3348: }
3349: c1 = codelem(e1,&retregs,FALSE);
3350: break;
3351: default:
3352: #ifdef DEBUG
3353: elem_print(e1);
3354: #endif
3355: assert(0);
3356: }
3357: reg = findreglsw(retregs);
3358: rm = I16 ? regtorm[reg] : regtorm32[reg];
3359: if (op16)
3360: seg |= CFopsize; // operand size
3361: if (npushes <= 4)
3362: {
3363: assert(!doneoff);
3364: for (c2 = CNIL; npushes > 1; npushes--)
3365: { c2 = genc1(c2,0xFF,buildModregrm(2,6,rm),FLconst,pushsize * (npushes - 1)); // PUSH [reg]
3366: code_orflag(c2,seg);
3367: genadjesp(c2,pushsize);
3368: }
3369: c3 = gen2(CNIL,0xFF,buildModregrm(0,6,rm)); // PUSH [reg]
3370: c3->Iflags |= seg;
3371: genadjesp(c3,pushsize);
3372: ce = cat4(cc,c1,c2,c3);
3373: }
3374: else if (sz)
3375: { int size;
3376:
3377: c2 = getregs_imm(mCX | retregs);
3378: /* MOV CX,sz/2 */
3379: c2 = movregconst(c2,CX,npushes,0);
3380: if (!doneoff)
3381: { /* This disgusting thing should be done when */
3382: /* reg is loaded. Too lazy to fix it now. */
3383: /* ADD reg,sz-2 */
3384: c2 = genc2(c2,0x81,grex | modregrmx(3,0,reg),sz-pushsize);
3385: }
3386: c3 = getregs(mCX); // the LOOP decrements it
3387: c3 = gen2(c3,0xFF,buildModregrm(0,6,rm)); // PUSH [reg]
3388: c3->Iflags |= seg | CFtarg2;
3389: genc2(c3,0x81,grex | buildModregrm(3,5,reg),pushsize); // SUB reg,2
3390: size = ((seg & CFSEG) ? -8 : -7) - op16;
3391: if (code_next(c3)->Iop != 0x81)
3392: size++;
3393: //genc2(c3,0xE2,0,size); // LOOP .-7 or .-8
3394: genjmp(c3,0xE2,FLcode,(block *)c3); // LOOP c3
3395: regimmed_set(CX,0);
3396: genadjesp(c3,sz);
3397: ce = cat4(cc,c1,c2,c3);
3398: }
3399: else
3400: ce = cat(cc,c1);
3401: stackpush += sz;
3402: goto L2;
3403: }
3404: case OPind:
3405: if (!e->Ecount) /* if *e1 */
3406: { if (sz <= REGSIZE)
warning C4018: '<=' : signed/unsigned mismatch
3407: { // Watch out for single byte quantities being up
3408: // against the end of a segment or in memory-mapped I/O
3409: if (!(config.exe & EX_flat) && szb == 1)
3410: break;
3411: goto L1; // can handle it with loadea()
3412: }
3413:
3414: // Avoid PUSH MEM on the Pentium when optimizing for speed
3415: if (config.flags4 & CFG4speed &&
3416: (config.target_cpu >= TARGET_80486 &&
3417: config.target_cpu <= TARGET_PentiumMMX) &&
3418: sz <= 2 * REGSIZE &&
warning C4018: '<=' : signed/unsigned mismatch
3419: !tyfloating(tym))
3420: break;
3421:
3422: if (tym == TYldouble || tym == TYildouble || tycomplex(tym))
3423: break;
3424: if (I32)
3425: {
3426: assert(sz == REGSIZE * 2);
3427: ce = loadea(e,&cs,0xFF,6,REGSIZE,0,0); /* PUSH EA+4 */
3428: ce = genadjesp(ce,REGSIZE);
3429: }
3430: else
3431: {
3432: if (sz == DOUBLESIZE)
3433: { ce = loadea(e,&cs,0xFF,6,DOUBLESIZE - REGSIZE,0,0); /* PUSH EA+6 */
3434: cs.IEVoffset1 -= REGSIZE;
3435: gen(ce,&cs); /* PUSH EA+4 */
3436: ce = genadjesp(ce,REGSIZE);
3437: getlvalue_lsw(&cs);
3438: gen(ce,&cs); /* PUSH EA+2 */
3439: }
3440: else /* TYlong */
3441: ce = loadea(e,&cs,0xFF,6,REGSIZE,0,0); /* PUSH EA+2 */
3442: ce = genadjesp(ce,REGSIZE);
3443: }
3444: stackpush += sz;
3445: getlvalue_lsw(&cs);
3446: gen(ce,&cs); /* PUSH EA */
3447: ce = genadjesp(ce,REGSIZE);
3448: goto L2;
3449: }
3450: break;
3451: case OPptrlptr:
3452: if (!e->Ecount) /* if (far *)e1 */
3453: {
3454: int segreg;
3455: tym_t tym1;
3456:
3457: e1 = e->E1;
3458: tym1 = tybasic(e1->Ety);
3459: /* BUG: what about pointers to functions? */
3460: segreg = (tym1 == TYnptr) ? 3<<3 :
3461: (tym1 == TYcptr) ? 1<<3 : 2<<3;
3462: if (I32 && stackalign == 2)
3463: c = gen1(c,0x66); /* push a word */
3464: c = gen1(c,0x06 + segreg); /* PUSH SEGREG */
3465: if (I32 && stackalign == 2)
3466: code_orflag(c,CFopsize); // push a word
3467: c = genadjesp(c,stackalign);
3468: stackpush += stackalign;
3469: ce = params(e1,stackalign);
3470: goto L2;
3471: }
3472: break;
3473: case OPrelconst:
3474: #if !TARGET_FLAT
3475: /* Determine if we can just push the segment register */
3476: /* Test size of type rather than TYfptr because of (long)(&v) */
3477: s = e->EV.sp.Vsym;
3478: //if (sytab[s->Sclass] & SCSS && !I32) // if variable is on stack
3479: // needframe = TRUE; // then we need stack frame
3480: if (tysize[tym] == tysize[TYfptr] &&
3481: (fl = s->Sfl) != FLfardata &&
3482: /* not a function that CS might not be the segment of */
3483: (!((fl == FLfunc || s->ty() & mTYcs) &&
3484: (s->Sclass == SCcomdat || s->Sclass == SCextern || s->Sclass == SCinline || config.wflags & WFthunk)) ||
3485: (fl == FLfunc && config.exe == EX_DOSX)
3486: )
3487: )
3488: {
3489: stackpush += sz;
3490: c = gen1(c,0x06 + /* PUSH SEGREG */
3491: (((fl == FLfunc || s->ty() & mTYcs) ? 1 : segfl[fl]) << 3));
3492: c = genadjesp(c,REGSIZE);
3493:
3494: if (config.target_cpu >= TARGET_80286 && !e->Ecount)
3495: { ce = getoffset(e,STACK);
3496: goto L2;
3497: }
3498: else
3499: { c = cat(c,offsetinreg(e,&retregs));
3500: unsigned reg = findreg(retregs);
3501: c = genpush(c,reg); // PUSH reg
3502: genadjesp(c,REGSIZE);
3503: }
3504: goto ret;
3505: }
3506: if (config.target_cpu >= TARGET_80286 && !e->Ecount)
3507: {
3508: stackpush += sz;
3509: if (tysize[tym] == tysize[TYfptr])
3510: {
3511: /* PUSH SEG e */
3512: code *c1 = gencs(CNIL,0x68,0,FLextern,s);
3513: c1->Iflags = CFseg;
3514: genadjesp(c1,REGSIZE);
3515: c = cat(c,c1);
3516: }
3517: ce = getoffset(e,STACK);
3518: goto L2;
3519: }
3520: #endif
3521: break; /* else must evaluate expression */
3522: case OPvar:
3523: L1:
3524: if (0 && I32 && sz == 2)
3525: { /* 32 bit code, but pushing 16 bit values anyway */
3526: ce = loadea(e,&cs,0xFF,6,0,0,0); /* PUSH EA */
3527: // BUG: 0x66 fails with scheduler
3528: ce = cat(gen1(CNIL,0x66),ce); /* 16 bit override */
3529: stackpush += sz;
3530: genadjesp(ce,sz);
3531: }
3532: else if (config.flags4 & CFG4speed &&
3533: (config.target_cpu >= TARGET_80486 &&
3534: config.target_cpu <= TARGET_PentiumMMX) &&
3535: sz <= 2 * REGSIZE &&
warning C4018: '<=' : signed/unsigned mismatch
3536: !tyfloating(tym))
3537: { // Avoid PUSH MEM on the Pentium when optimizing for speed
3538: break;
3539: }
3540: else
3541: { int regsize = REGSIZE;
3542: unsigned flag = 0;
3543:
3544: if (I16 && config.target_cpu >= TARGET_80386 && sz > 2 &&
3545: !e->Ecount)
3546: { regsize = 4;
3547: flag |= CFopsize;
3548: }
3549: ce = loadea(e,&cs,0xFF,6,sz - regsize,RMload,0); // PUSH EA+sz-2
3550: code_orflag(ce,flag);
3551: ce = genadjesp(ce,REGSIZE);
3552: stackpush += sz;
3553: while ((targ_int)(sz -= regsize) > 0)
3554: { ce = cat(ce,loadea(e,&cs,0xFF,6,sz - regsize,RMload,0));
3555: code_orflag(ce,flag);
3556: ce = genadjesp(ce,REGSIZE);
3557: }
3558: }
3559: L2:
3560: freenode(e);
3561: c = cat(c,ce);
3562: goto ret;
3563: case OPconst:
3564: {
3565: char pushi = 0;
3566: unsigned flag = 0;
3567: int regsize = REGSIZE;
3568: targ_int value;
3569:
3570: if (tycomplex(tym))
3571: break;
3572:
3573: if (I64 && tyfloating(tym) && sz > 4 && boolres(e))
3574: // Can't push 64 bit non-zero args directly
3575: break;
3576:
3577: if (I32 && szb == 10) // special case for long double constants
3578: {
3579: assert(sz == 12);
3580: value = ((unsigned short *)&e->EV.Vldouble)[4];
3581: stackpush += sz;
3582: ce = genadjesp(NULL,sz);
3583: for (int i = 2; i >= 0; i--)
3584: {
3585: if (reghasvalue(allregs, value, ®))
3586: ce = gen1(ce,0x50 + reg); // PUSH reg
3587: else
3588: ce = genc2(ce,0x68,0,value); // PUSH value
3589: value = ((unsigned *)&e->EV.Vldouble)[i - 1];
3590: }
3591: goto L2;
3592: }
3593:
3594: assert(I64 || sz <= LNGDBLSIZE);
3595: int i = sz;
3596: if (!I16 && i == 2)
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
3597: flag = CFopsize;
3598:
3599: if (config.target_cpu >= TARGET_80286)
3600: // && (e->Ecount == 0 || e->Ecount != e->Ecomsub))
3601: { pushi = 1;
3602: if (I16 && config.target_cpu >= TARGET_80386 && i >= 4)
3603: { regsize = 4;
3604: flag = CFopsize;
3605: }
3606: }
3607: else if (i == REGSIZE)
3608: break;
3609:
3610: stackpush += sz;
3611: ce = genadjesp(NULL,sz);
3612: targ_uns *pi = (targ_uns *) &e->EV.Vdouble;
3613: targ_ushort *ps = (targ_ushort *) pi;
3614: targ_ullong *pl = (targ_ullong *)pi;
3615: i /= regsize;
3616: do
3617: {
3618: if (i) /* be careful not to go negative */
3619: i--;
3620: targ_size_t value = (regsize == 4) ? pi[i] : ps[i];
warning C6246: Local declaration of 'value' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '3568' of 'c:\projects\extern\d\dmd\src\backend\cod1.c': Lines: 3568
3621: if (regsize == 8)
3622: value = pl[i];
warning C4244: '=' : conversion from 'targ_ullong' to 'targ_size_t', possible loss of data
3623: if (pushi)
3624: {
3625: if (I64 && regsize == 8 && value != (int)value)
3626: { ce = regwithvalue(ce,allregs,value,®,64);
3627: goto Preg; // cannot push imm64 unless it is sign extended 32 bit value
3628: }
3629: if (regsize == REGSIZE && reghasvalue(allregs,value,®))
3630: goto Preg;
3631: ce = genc2(ce,(szb == 1) ? 0x6A : 0x68,0,value); // PUSH value
3632: }
3633: else
3634: {
3635: ce = regwithvalue(ce,allregs,value,®,0);
3636: Preg:
3637: ce = genpush(ce,reg); // PUSH reg
3638: }
3639: code_orflag(ce,flag); /* operand size */
3640: } while (i);
3641: goto L2;
3642: }
3643: default:
3644: break;
3645: }
3646: retregs = tybyte(tym) ? BYTEREGS : allregs;
3647: if (tyfloating(tym))
3648: { if (config.inline8087)
3649: { code *c1,*c2;
3650: unsigned op;
3651: unsigned r;
3652:
3653: retregs = tycomplex(tym) ? mST01 : mST0;
3654: c = cat(c,codelem(e,&retregs,FALSE));
3655: stackpush += sz;
3656: c = genadjesp(c,sz);
3657: c = genc2(c,0x81,grex | modregrm(3,5,SP),sz); // SUB SP,sz
3658: switch (tym)
3659: {
3660: case TYfloat:
3661: case TYifloat:
3662: case TYcfloat:
3663: op = 0xD9;
3664: r = 3;
3665: break;
3666:
3667: case TYdouble:
3668: case TYidouble:
3669: case TYdouble_alias:
3670: case TYcdouble:
3671: op = 0xDD;
3672: r = 3;
3673: break;
3674:
3675: case TYldouble:
3676: case TYildouble:
3677: case TYcldouble:
3678: op = 0xDB;
3679: r = 7;
3680: break;
3681:
3682: default:
3683: assert(0);
3684: }
3685: if (!I16)
3686: {
3687: c1 = NULL;
3688: c2 = NULL;
3689: if (tycomplex(tym))
3690: {
3691: // FSTP sz/2[ESP]
3692: c2 = genc1(CNIL,op,(modregrm(0,4,SP) << 8) | modregxrm(2,r,4),FLconst,sz/2);
3693: pop87();
3694: }
3695: pop87();
3696: c2 = gen2sib(c2,op,modregrm(0,r,4),modregrm(0,4,SP)); // FSTP [ESP]
3697: }
3698: else
3699: {
3700: retregs = IDXREGS; /* get an index reg */
3701: c1 = allocreg(&retregs,®,TYoffset);
3702: c1 = genregs(c1,0x89,SP,reg); /* MOV reg,SP */
3703: pop87();
3704: c2 = gen2(CNIL,op,modregrm(0,r,regtorm[reg])); // FSTP [reg]
3705: }
3706: if (LARGEDATA)
3707: c2->Iflags |= CFss; /* want to store into stack */
3708: genfwait(c2); // FWAIT
3709: c = cat3(c,c1,c2);
3710: goto ret;
3711: }
3712: else if (I16 && (tym == TYdouble || tym == TYdouble_alias))
3713: retregs = mSTACK;
3714: }
3715: #if LONGLONG
3716: else if (I16 && sz == 8) // if long long
3717: retregs = mSTACK;
3718: #endif
3719: c = cat(c,scodelem(e,&retregs,0,TRUE));
3720: if (retregs != mSTACK) /* if stackpush not already inc'd */
3721: stackpush += sz;
3722: if (sz <= REGSIZE)
warning C4018: '<=' : signed/unsigned mismatch
3723: {
3724: c = genpush(c,findreg(retregs)); // PUSH reg
3725: genadjesp(c,REGSIZE);
3726: }
3727: else if (sz == REGSIZE * 2)
3728: { c = genpush(c,findregmsw(retregs)); // PUSH msreg
3729: genpush(c,findreglsw(retregs)); // PUSH lsreg
3730: genadjesp(c,sz);
3731: }
3732: ret:
3733: return cat(cp,c);
3734: }
3735:
3736:
3737: /*******************************
3738: * Get offset portion of e, and store it in an index
3739: * register. Return mask of index register in *pretregs.
3740: */
3741:
3742: code *offsetinreg( elem *e, regm_t *pretregs)
3743: { regm_t retregs;
3744: code *c;
3745: unsigned reg;
3746:
3747: retregs = mLSW; /* want only offset */
3748: if (e->Ecount && e->Ecount != e->Ecomsub)
3749: { unsigned i;
3750: regm_t rm;
3751:
3752: rm = retregs & regcon.cse.mval & ~regcon.cse.mops & ~regcon.mvar; /* possible regs */
3753: for (i = 0; rm; i++)
3754: { if (mask[i] & rm && regcon.cse.value[i] == e)
3755: { reg = i;
3756: *pretregs = mask[i];
3757: c = getregs(*pretregs);
3758: goto L3;
3759: }
3760: rm &= ~mask[i];
3761: }
3762: }
3763:
3764: *pretregs = retregs;
3765: c = allocreg(pretregs,®,TYoffset);
3766: c = cat(c,getoffset(e,reg));
3767: L3:
3768: cssave(e,*pretregs,FALSE);
3769: freenode(e);
3770: return c;
3771: }
3772:
3773:
3774: /******************************
3775: * Generate code to load data into registers.
3776: */
3777:
3778: code *loaddata(elem *e,regm_t *pretregs)
3779: { unsigned reg,nreg,op,sreg;
3780: tym_t tym;
3781: int sz;
3782: code *c,*ce,cs;
3783: regm_t flags,forregs,regm;
3784:
3785: #ifdef DEBUG
3786: if (debugw)
3787: printf("loaddata(e = %p,*pretregs = %s)\n",e,regm_str(*pretregs));
3788: //elem_print(e);
3789: #endif
3790: assert(e);
3791: elem_debug(e);
3792: if (*pretregs == 0)
3793: return CNIL;
3794: tym = tybasic(e->Ety);
3795: if (tym == TYstruct)
3796: return cdrelconst(e,pretregs);
3797: if (tyfloating(tym))
3798: { obj_fltused();
3799: if (config.inline8087)
3800: { if (*pretregs & mST0)
3801: return load87(e,0,pretregs,NULL,-1);
3802: else if (tycomplex(tym))
3803: return cload87(e, pretregs);
3804: }
3805: }
3806: sz = tysize[tym];
3807: cs.Iflags = 0;
3808: cs.Irex = 0;
3809: if (*pretregs == mPSW)
3810: {
3811: regm = allregs;
3812: if (e->Eoper == OPconst)
3813: { /* TRUE: OR SP,SP (SP is never 0) */
3814: /* FALSE: CMP SP,SP (always equal) */
3815: c = genregs(CNIL,(boolres(e)) ? 0x09 : 0x39,SP,SP);
3816: if (I64)
3817: code_orrex(c, REX_W);
3818: }
3819: else if (sz <= REGSIZE)
3820: {
3821: if (!I16 && (tym == TYfloat || tym == TYifloat))
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
3822: { c = allocreg(®m,®,TYoffset); /* get a register */
3823: ce = loadea(e,&cs,0x8B,reg,0,0,0); // MOV reg,data
3824: c = cat(c,ce);
3825: ce = gen2(CNIL,0xD1,modregrmx(3,4,reg)); /* SHL reg,1 */
3826: c = cat(c,ce);
3827: }
3828: else
3829: { cs.IFL2 = FLconst;
3830: cs.IEV2.Vsize_t = 0;
3831: op = (sz == 1) ? 0x80 : 0x81;
3832: c = loadea(e,&cs,op,7,0,0,0); /* CMP EA,0 */
3833:
3834: // Convert to TEST instruction if EA is a register
3835: // (to avoid register contention on Pentium)
3836: if ((c->Iop & ~1) == 0x38 &&
3837: (c->Irm & modregrm(3,0,0)) == modregrm(3,0,0)
3838: )
3839: { c->Iop = (c->Iop & 1) | 0x84;
3840: code_newreg(c, c->Irm & 7);
3841: if (c->Irex & REX_B)
3842: //c->Irex = (c->Irex & ~REX_B) | REX_R;
3843: c->Irex |= REX_R;
3844: }
3845: }
3846: }
3847: else if (sz < 8)
3848: {
3849: c = allocreg(®m,®,TYoffset); /* get a register */
3850: if (I32) // it's a 48 bit pointer
3851: ce = loadea(e,&cs,0x0FB7,reg,REGSIZE,0,0); /* MOVZX reg,data+4 */
3852: else
3853: { ce = loadea(e,&cs,0x8B,reg,REGSIZE,0,0); /* MOV reg,data+2 */
3854: if (tym == TYfloat || tym == TYifloat) // dump sign bit
3855: gen2(ce,0xD1,modregrm(3,4,reg)); /* SHL reg,1 */
3856: }
3857: c = cat(c,ce);
3858: ce = loadea(e,&cs,0x0B,reg,0,regm,0); /* OR reg,data */
3859: c = cat(c,ce);
3860: }
3861: else if (sz == 8 || (I64 && sz == 2 * REGSIZE && !tyfloating(tym)))
3862: {
3863: c = allocreg(®m,®,TYoffset); /* get a register */
3864: int i = sz - REGSIZE;
3865: ce = loadea(e,&cs,0x8B,reg,i,0,0); /* MOV reg,data+6 */
3866: if (tyfloating(tym)) // TYdouble or TYdouble_alias
3867: gen2(ce,0xD1,modregrm(3,4,reg)); // SHL reg,1
3868: c = cat(c,ce);
3869:
3870: while ((i -= REGSIZE) >= 0)
3871: {
3872: code *c1 = loadea(e,&cs,0x0B,reg,i,regm,0); // OR reg,data+i
3873: if (i == 0)
3874: c1->Iflags |= CFpsw; // need the flags on last OR
3875: c = cat(c,c1);
3876: }
3877: }
3878: else if (sz == tysize[TYldouble]) // TYldouble
3879: return load87(e,0,pretregs,NULL,-1);
3880: else
3881: {
3882: #ifdef DEBUG
3883: elem_print(e);
3884: #endif
3885: assert(0);
3886: }
3887: return c;
3888: }
3889: /* not for flags only */
3890: flags = *pretregs & mPSW; /* save original */
3891: forregs = *pretregs & (mBP | ALLREGS | mES | XMMREGS);
3892: if (*pretregs & mSTACK)
3893: forregs |= DOUBLEREGS;
3894: if (e->Eoper == OPconst)
3895: {
3896: targ_size_t value = e->EV.Vint;
3897: if (sz == 8)
3898: value = e->EV.Vullong;
warning C4244: '=' : conversion from 'targ_ullong' to 'targ_size_t', possible loss of data
3899:
3900: if (sz == REGSIZE && reghasvalue(forregs,value,®))
3901: forregs = mask[reg];
3902:
3903: regm_t save = regcon.immed.mval;
3904: c = allocreg(&forregs,®,tym); /* allocate registers */
3905: regcon.immed.mval = save; // KLUDGE!
3906: if (sz <= REGSIZE)
3907: {
3908: if (sz == 1)
3909: flags |= 1;
3910: else 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?
3911: !(mask[reg] & regcon.mvar) &&
3912: !(config.flags4 & CFG4speed)
3913: )
3914: flags |= 2;
3915: if (sz == 8)
3916: flags |= 64;
3917: if (reg >= XMM0)
3918: { /* This comes about because 0, 1, pi, etc., constants don't get stored
3919: * in the data segment, because they are x87 opcodes.
3920: * Not so efficient. We should at least do a PXOR for 0.
3921: */
3922: unsigned r;
3923: targ_size_t value = e->EV.Vuns;
warning C6246: Local declaration of 'value' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '3896' of 'c:\projects\extern\d\dmd\src\backend\cod1.c': Lines: 3896
3924: if (sz == 8)
3925: value = e->EV.Vullong;
warning C4244: '=' : conversion from 'targ_ullong' to 'targ_size_t', possible loss of data
3926: ce = regwithvalue(CNIL,ALLREGS,value,&r,flags);
3927: flags = 0; // flags are already set
3928: ce = genfltreg(ce,0x89,r,0); // MOV floatreg,r
3929: if (sz == 8)
3930: code_orrex(ce, REX_W);
3931: assert(sz == 4 || sz == 8); // float or double
3932: unsigned op = (sz == 4) ? 0xF30F10 : 0xF20F10;
warning C6246: Local declaration of 'op' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '3779' of 'c:\projects\extern\d\dmd\src\backend\cod1.c': Lines: 3779
3933: ce = genfltreg(ce,op,reg - XMM0,0); // MOVSS/MOVSD XMMreg,floatreg
3934: }
3935: else
3936: { ce = movregconst(CNIL,reg,value,flags);
3937: flags = 0; // flags are already set
3938: }
3939: }
3940: else if (sz < 8) // far pointers, longs for 16 bit targets
3941: {
3942: targ_int msw,lsw;
3943: regm_t mswflags;
3944:
3945: msw = I32 ? e->EV.Vfp.Vseg
3946: : (e->EV.Vulong >> 16);
3947: lsw = e->EV.Vfp.Voff;
3948: mswflags = 0;
3949: if (forregs & mES)
3950: {
3951: ce = movregconst(CNIL,reg,msw,0); // MOV reg,segment
3952: genregs(ce,0x8E,0,reg); // MOV ES,reg
3953: msw = lsw; // MOV reg,offset
3954: }
3955: else
3956: {
3957: sreg = findreglsw(forregs);
3958: ce = movregconst(CNIL,sreg,lsw,0);
3959: reg = findregmsw(forregs);
3960: /* Decide if we need to set flags when we load msw */
3961: if (flags && (msw && msw|lsw || !(msw|lsw)))
3962: { mswflags = mPSW;
3963: flags = 0;
3964: }
3965: }
3966: ce = movregconst(ce,reg,msw,mswflags);
3967: }
3968: else if (sz == 8)
3969: {
3970: if (I32)
3971: { targ_long *p = (targ_long *) &e->EV.Vdouble;
3972: ce = movregconst(CNIL,findreglsw(forregs),p[0],0);
3973: ce = movregconst(ce,findregmsw(forregs),p[1],0);
3974: }
3975: else
3976: { targ_short *p = (targ_short *) &e->EV.Vdouble;
3977:
3978: assert(reg == AX);
3979: ce = movregconst(CNIL,AX,p[3],0); /* MOV AX,p[3] */
3980: ce = movregconst(ce,DX,p[0],0);
3981: ce = movregconst(ce,CX,p[1],0);
3982: ce = movregconst(ce,BX,p[2],0);
3983: }
3984: }
3985: else if (I64 && sz == 16)
3986: {
3987: ce = movregconst(CNIL,findreglsw(forregs),e->EV.Vcent.lsw,0);
warning C4244: 'argument' : conversion from 'targ_ullong' to 'targ_size_t', possible loss of data
3988: ce = movregconst(ce,findregmsw(forregs),e->EV.Vcent.msw,0);
warning C4244: 'argument' : conversion from 'targ_ullong' to 'targ_size_t', possible loss of data
3989: }
3990: else
3991: assert(0);
3992: c = cat(c,ce);
3993: }
3994: else
3995: {
3996: // See if we can use register that parameter was passed in
3997: if (regcon.params && e->EV.sp.Vsym->Sclass == SCfastpar &&
3998: regcon.params & mask[e->EV.sp.Vsym->Spreg] &&
3999: !(e->Eoper == OPvar && e->EV.sp.Voffset > 0) && // Must be at the base of that variable
4000: sz <= REGSIZE) // make sure no 'paint' to a larger size happened
4001: {
4002: reg = e->EV.sp.Vsym->Spreg;
4003: forregs = mask[reg];
4004: mfuncreg &= ~forregs;
4005: regcon.used |= forregs;
4006: return fixresult(e,forregs,pretregs);
4007: }
4008:
4009: c = allocreg(&forregs,®,tym); /* allocate registers */
4010:
4011: if (sz == 1)
4012: { regm_t nregm;
4013:
4014: #ifdef DEBUG
4015: if (!(forregs & BYTEREGS))
4016: { elem_print(e);
4017: printf("forregs = x%x\n",forregs);
4018: }
4019: #endif
4020: assert(forregs & BYTEREGS);
4021: if (!I16)
4022: c = cat(c,loadea(e,&cs,0x8A,reg,0,0,0)); // MOV regL,data
4023: else
4024: { nregm = tyuns(tym) ? BYTEREGS : mAX;
4025: if (*pretregs & nregm)
4026: nreg = reg; /* already allocated */
4027: else
4028: c = cat(c,allocreg(&nregm,&nreg,tym));
4029: ce = loadea(e,&cs,0x8A,nreg,0,0,0); /* MOV nregL,data */
4030: c = cat(c,ce);
4031: if (reg != nreg)
4032: { genmovreg(c,reg,nreg); /* MOV reg,nreg */
4033: cssave(e,mask[nreg],FALSE);
4034: }
4035: }
4036: }
4037: else if (forregs & XMMREGS)
4038: {
4039: // Can't load from registers directly to XMM regs
4040: e->EV.sp.Vsym->Sflags &= ~GTregcand;
4041:
4042: assert(sz == 4 || sz == 8); // float or double
4043: unsigned op = (sz == 4) ? 0xF30F10 : 0xF20F10;
warning C6246: Local declaration of 'op' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '3779' of 'c:\projects\extern\d\dmd\src\backend\cod1.c': Lines: 3779
4044: ce = loadea(e,&cs,op,reg,0,RMload,0); // MOVSS/MOVSD reg,data
4045: c = cat(c,ce);
4046: }
4047: else if (sz <= REGSIZE)
4048: {
4049: ce = loadea(e,&cs,0x8B,reg,0,RMload,0); // MOV reg,data
4050: c = cat(c,ce);
4051: }
4052: else if (sz <= 2 * REGSIZE && forregs & mES)
4053: {
4054: ce = loadea(e,&cs,0xC4,reg,0,0,mES); /* LES data */
4055: c = cat(c,ce);
4056: }
4057: else if (sz <= 2 * REGSIZE)
4058: {
4059: if (I32 && sz == 8 &&
4060: (*pretregs & (mSTACK | mPSW)) == mSTACK)
4061: { int i;
4062:
4063: assert(0);
4064: /* Note that we allocreg(DOUBLEREGS) needlessly */
4065: stackchanged = 1;
4066: i = DOUBLESIZE - REGSIZE;
4067: do
4068: { c = cat(c,loadea(e,&cs,0xFF,6,i,0,0)); /* PUSH EA+i */
4069: c = genadjesp(c,REGSIZE);
4070: stackpush += REGSIZE;
4071: i -= REGSIZE;
4072: }
4073: while (i >= 0);
4074: return c;
4075: }
4076:
4077: reg = findregmsw(forregs);
4078: ce = loadea(e,&cs,0x8B,reg,REGSIZE,forregs,0); /* MOV reg,data+2 */
4079: if (I32 && sz == REGSIZE + 2)
4080: ce->Iflags |= CFopsize; /* seg is 16 bits */
4081: c = cat(c,ce);
4082: reg = findreglsw(forregs);
4083: ce = loadea(e,&cs,0x8B,reg,0,forregs,0);
4084: c = cat(c,ce);
4085: }
4086: else if (sz >= 8)
4087: {
4088: code *c1,*c2,*c3;
4089:
4090: assert(!I32);
4091: if ((*pretregs & (mSTACK | mPSW)) == mSTACK)
4092: { int i;
4093:
4094: /* Note that we allocreg(DOUBLEREGS) needlessly */
4095: stackchanged = 1;
4096: i = sz - REGSIZE;
4097: do
4098: { c = cat(c,loadea(e,&cs,0xFF,6,i,0,0)); /* PUSH EA+i */
4099: c = genadjesp(c,REGSIZE);
4100: stackpush += REGSIZE;
4101: i -= REGSIZE;
4102: }
4103: while (i >= 0);
4104: return c;
4105: }
4106: else
4107: {
4108: assert(reg == AX);
4109: ce = loadea(e,&cs,0x8B,AX,6,0,0); /* MOV AX,data+6 */
4110: c1 = loadea(e,&cs,0x8B,BX,4,mAX,0); /* MOV BX,data+4 */
4111: c2 = loadea(e,&cs,0x8B,CX,2,mAX|mBX,0); /* MOV CX,data+2 */
4112: c3 = loadea(e,&cs,0x8B,DX,0,mAX|mCX|mCX,0); /* MOV DX,data */
4113: c = cat6(c,ce,c1,c2,c3,CNIL);
4114: }
4115: }
4116: else
4117: assert(0);
4118: }
4119: /* Flags may already be set */
4120: *pretregs &= flags | ~mPSW;
4121: c = cat(c,fixresult(e,forregs,pretregs));
4122: return c;
4123: }
4124:
4125: #endif // SPP
4126: