1: // Copyright (C) 1985-1998 by Symantec
2: // Copyright (C) 2000-2009 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: #include "exh.h"
33:
34: static char __file__[] = __FILE__; /* for tassert.h */
35: #include "tassert.h"
36:
37: STATIC void resetEcomsub(elem *e);
38: STATIC code * loadcse(elem *,unsigned,regm_t);
39: STATIC void blcodgen(block *);
40: STATIC void cgcod_eh();
41: STATIC code * cse_save(regm_t ms);
42: STATIC int cse_simple(elem *e,int i);
43: STATIC code * comsub(elem *,regm_t *);
44:
45: bool floatreg; // !=0 if floating register is required
46:
47: targ_size_t Aoffset; // offset of automatics and registers
48: targ_size_t Toffset; // offset of temporaries
49: targ_size_t EEoffset; // offset of SCstack variables from ESP
50: int Aalign; // alignment for Aoffset
51:
52: REGSAVE regsave;
53:
54: CGstate cgstate; // state of code generator
55:
56: /************************************
57: * # of bytes that SP is beyond BP.
58: */
59:
60: unsigned stackpush;
61:
62: int stackchanged; /* set to !=0 if any use of the stack
63: other than accessing parameters. Used
64: to see if we can address parameters
65: with ESP rather than EBP.
66: */
67: int refparam; // !=0 if we referenced any parameters
68: int reflocal; // !=0 if we referenced any locals
69: char anyiasm; // !=0 if any inline assembler
70: char calledafunc; // !=0 if we called a function
71: char needframe; // if TRUE, then we will need the frame
72: // pointer (BP for the 8088)
73: char usedalloca; // if TRUE, then alloca() was called
74: char gotref; // !=0 if the GOTsym was referenced
75: unsigned usednteh; // if !=0, then used NT exception handling
76:
77: /* Register contents */
78: con_t regcon;
79:
80: int pass; // PASSxxxx
81:
82: static symbol *retsym; // set to symbol that should be placed in
83: // register AX
84:
85: /****************************
86: * Register masks.
87: */
88:
89: regm_t msavereg; // Mask of registers that we would like to save.
90: // they are temporaries (set by scodelem())
91: regm_t mfuncreg; // Mask of registers preserved by a function
92: regm_t allregs; // ALLREGS optionally including mBP
93:
94: int dfoidx; /* which block we are in */
95: struct CSE *csextab = NULL; /* CSE table (allocated for each function) */
96: unsigned cstop; /* # of entries in CSE table (csextab[]) */
97: unsigned csmax; /* amount of space in csextab[] */
98:
99: targ_size_t funcoffset; // offset of start of function
100: targ_size_t startoffset; // size of function entry code
101: targ_size_t retoffset; /* offset from start of func to ret code */
102: targ_size_t retsize; /* size of function return */
103:
104: static regm_t lastretregs,last2retregs,last3retregs,last4retregs,last5retregs;
105:
106: /*********************************
107: * Generate code for a function.
108: * Note at the end of this routine mfuncreg will contain the mask
109: * of registers not affected by the function. Some minor optimization
110: * possibilities are here...
111: */
112:
113: void codgen()
114: { block *b,*bn;
115: bool flag;
116: int i;
117: targ_size_t swoffset,coffset;
118: tym_t functy;
119: unsigned nretblocks; // number of return blocks
120: code *cprolog;
121: regm_t noparams;
122: #if SCPP
123: block *btry;
124: #endif
125: // Register usage. If a bit is on, the corresponding register is live
126: // in that basic block.
127:
128: //printf("codgen('%s')\n",funcsym_p->Sident);
129:
130: cgreg_init();
131: csmax = 64;
132: csextab = (struct CSE *) util_calloc(sizeof(struct CSE),csmax);
133: functy = tybasic(funcsym_p->ty());
134: #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
135: if (0 && config.flags3 & CFG3pic)
136: {
137: ALLREGS = ALLREGS_INIT_PIC;
138: BYTEREGS = BYTEREGS_INIT_PIC;
139: }
140: else
141: {
142: regm_t value = BYTEREGS_INIT;
143: ALLREGS = ALLREGS_INIT;
144: BYTEREGS = value;
145: }
146: if (I64)
147: { ALLREGS = mAX|mBX|mCX|mDX|mSI|mDI| mR8|mR9|mR10|mR11|mR12|mR13|mR14|mR15;
148: BYTEREGS = ALLREGS;
149: }
150: #endif
151: allregs = ALLREGS;
152: if (0 && config.flags3 & CFG3pic)
153: allregs &= ~mBX;
154: pass = PASSinit;
155:
156: tryagain:
157: #ifdef DEBUG
158: if (debugr)
159: printf("------------------ PASS%s -----------------\n",
160: (pass == PASSinit) ? "init" : ((pass == PASSreg) ? "reg" : "final"));
161: #endif
162: lastretregs = last2retregs = last3retregs = last4retregs = last5retregs = 0;
163:
164: // if no parameters, assume we don't need a stack frame
165: needframe = 0;
166: usedalloca = 0;
167: gotref = 0;
168: stackchanged = 0;
169: stackpush = 0;
170: refparam = 0;
171: anyiasm = 0;
172: calledafunc = 0;
173: cgstate.stackclean = 1;
174: retsym = NULL;
175:
176: regsave.reset();
177: memset(_8087elems,0,sizeof(_8087elems));
178:
179: usednteh = 0;
180: #if (MARS) && TARGET_WINDOS
181: if (funcsym_p->Sfunc->Fflags3 & Fjmonitor)
182: usednteh |= NTEHjmonitor;
183: #else
184: if (CPP)
185: {
186: if (config.flags2 & CFG2seh &&
187: (funcsym_p->Stype->Tflags & TFemptyexc || funcsym_p->Stype->Texcspec))
188: usednteh |= NTEHexcspec;
189: except_reset();
190: }
191: #endif
192:
193: floatreg = FALSE;
194: assert(stackused == 0); /* nobody in 8087 stack */
195: cstop = 0; /* no entries in table yet */
196: memset(®con,0,sizeof(regcon));
197: regcon.cse.mval = regcon.cse.mops = 0; // no common subs yet
198: #if 0 && TARGET_LINUX
199: if (!(allregs & mBX))
200: msavereg = mBX;
201: else
202: #endif
203: msavereg = 0;
204: nretblocks = 0;
205: mfuncreg = fregsaved; // so we can see which are used
206: // (bit is cleared each time
207: // we use one)
208: for (b = startblock; b; b = b->Bnext)
209: { memset(&b->Bregcon,0,sizeof(b->Bregcon)); // Clear out values in registers
210: if (b->Belem)
211: resetEcomsub(b->Belem); // reset all the Ecomsubs
212: if (b->BC == BCasm)
213: anyiasm = 1; // we have inline assembler
214: if (b->BC == BCret || b->BC == BCretexp)
215: nretblocks++;
216: }
217:
218: if (!config.fulltypes || (config.flags4 & CFG4optimized))
219: {
220: noparams = 0;
221: for (i = 0; i < globsym.top; i++)
222: {
223: Symbol *s = globsym.tab[i];
224: s->Sflags &= ~SFLread;
225: switch (s->Sclass)
226: { case SCfastpar:
227: regcon.params |= mask[s->Spreg];
228: case SCparameter:
229: if (s->Sfl == FLreg)
230: noparams |= s->Sregm;
231: break;
232: }
233: }
234: regcon.params &= ~noparams;
235: }
236:
237: if (config.flags4 & CFG4optimized)
238: {
239: if (nretblocks == 0 && // if no return blocks in function
240: !(funcsym_p->ty() & mTYnaked)) // naked functions may have hidden veys of returning
241: funcsym_p->Sflags |= SFLexit; // mark function as never returning
242:
243: assert(dfo);
244:
245: cgreg_reset();
246: for (dfoidx = 0; dfoidx < dfotop; dfoidx++)
warning C4018: '<' : signed/unsigned mismatch
247: { regcon.used = msavereg | regcon.cse.mval; // registers already in use
248: b = dfo[dfoidx];
249: blcodgen(b); // gen code in depth-first order
250: //printf("b->Bregcon.used = x%x\n", b->Bregcon.used);
251: cgreg_used(dfoidx,b->Bregcon.used); // gather register used information
252: }
253: }
254: else
255: { pass = PASSfinal;
256: for (b = startblock; b; b = b->Bnext)
257: blcodgen(b); // generate the code for each block
258: }
259: regcon.immed.mval = 0;
260: assert(!regcon.cse.mops); // should have all been used
261:
262: // See which variables we can put into registers
263: if (pass != PASSfinal &&
264: !anyiasm) // possible LEA or LES opcodes
265: {
266: allregs |= cod3_useBP(); // see if we can use EBP
267:
268: // If pic code, but EBX was never needed
269: if (!(allregs & mBX) && !gotref)
270: { allregs |= mBX; // EBX can now be used
271: cgreg_assign(retsym);
272: pass = PASSreg;
273: }
274: else if (cgreg_assign(retsym)) // if we found some registers
275: pass = PASSreg;
276: else
277: pass = PASSfinal;
278: for (b = startblock; b; b = b->Bnext)
279: { code_free(b->Bcode);
280: b->Bcode = NULL;
281: }
282: goto tryagain;
283: }
284: cgreg_term();
285:
286: #if SCPP
287: if (CPP)
288: cgcod_eh();
289: #endif
290:
291: stackoffsets(1); // compute addresses of stack variables
292: cod5_prol_epi(); // see where to place prolog/epilog
293:
294: // Get rid of unused cse temporaries
295: while (cstop != 0 && (csextab[cstop - 1].flags & CSEload) == 0)
296: cstop--;
297:
298: if (configv.addlinenumbers)
299: objlinnum(funcsym_p->Sfunc->Fstartline,Coffset);
300:
301: // Otherwise, jmp's to startblock will execute the prolog again
302: assert(!startblock->Bpred);
warning C6011: Dereferencing NULL pointer 'struct block * startblock': Lines: 114, 115, 116, 117, 118, 119, 120, 121, 130, 131, 132, 133, 151, 152, 154, 156, 162, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 176, 177, 179, 181, 182, 193, 194, 195, 196, 197, 203, 204, 205, 208, 218, 220, 221, 234, 237, 239, 241, 243, 245, 246, 259, 260, 263,266, 269, 270, 271, 272, 278, 282, 156, 162, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 176, 177, 179, 181, 182, 193, 194, 195, 196, 197, 203, 204, 205, 208, 218, 220, 221, 234, 237, 239, 241, 243, 245, 246, 259, 260, 263, 266, 269, 270, 271, 272, 278, 282, 156, 162, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 176, 177, 179, 181, 182, 193, 194, 195, 196, 197, 203, 204, 205, 208, 218, 220, 221, 234, 237, 255, 256, 259, 260, 263, 284, 291, 292, 295, 298, 299, 302
303:
304: cprolog = prolog(); // gen function start code
305: if (cprolog)
306: pinholeopt(cprolog,NULL); // optimize
307:
308: funcoffset = Coffset;
309: coffset = Coffset;
310:
311: if (eecontext.EEelem)
312: { regm_t retregs;
313: code *c;
314:
315: eecontext.EEin++;
316: regcon.immed.mval = 0;
317: retregs = 0; //regmask(eecontext.EEelem->Ety);
318: assert(EEoffset >= REGSIZE);
warning C4018: '>=' : signed/unsigned mismatch
319: c = genc2(NULL,0x81,modregrm(3,5,SP),EEoffset - REGSIZE); // SUB ESP,EEoffset
320: gen1(c,0x50 + SI); // PUSH ESI
321: genadjesp(c,EEoffset);
322: c = gencodelem(c,eecontext.EEelem,&retregs, FALSE);
323: assignaddrc(c);
324: pinholeopt(c,NULL);
325: jmpaddr(c);
326: eecontext.EEcode = gen1(c,0xCC); // INT 3
327: eecontext.EEin--;
328: }
329:
330: for (b = startblock; b; b = b->Bnext)
331: {
332: // We couldn't do this before because localsize was unknown
333: switch (b->BC)
334: { case BCret:
335: if (configv.addlinenumbers && b->Bsrcpos.Slinnum && !(funcsym_p->ty() & mTYnaked))
336: cgen_linnum(&b->Bcode,b->Bsrcpos);
337: case BCretexp:
338: epilog(b);
339: break;
340: default:
341: if (b->Bflags & BFLepilog)
342: epilog(b);
343: break;
344: }
345: assignaddr(b); // assign addresses
346: pinholeopt(b->Bcode,b); // do pinhole optimization
347: if (b->Bflags & BFLprolog) // do function prolog
348: {
349: startoffset = coffset + calcblksize(cprolog) - funcoffset;
350: b->Bcode = cat(cprolog,b->Bcode);
351: }
352: if (config.flags4 & CFG4speed &&
353: config.target_cpu >= TARGET_Pentium &&
354: b->BC != BCasm
355: )
356: { regm_t scratch;
357:
358: scratch = allregs & ~(b->Bregcon.used | b->Bregcon.params | mfuncreg);
359: scratch &= ~(b->Bregcon.immed.mval | b->Bregcon.cse.mval);
360: cgsched_pentium(&b->Bcode,scratch);
361: //printf("after schedule:\n"); WRcodlst(b->Bcode);
362: }
363: b->Bsize = calcblksize(b->Bcode); // calculate block size
364: if (b->Balign)
365: { targ_size_t u = b->Balign - 1;
366:
367: coffset = (coffset + u) & ~u;
368: }
369: b->Boffset = coffset; /* offset of this block */
370: coffset += b->Bsize; /* offset of following block */
371: }
372: #ifdef DEBUG
373: debugw && printf("code addr complete\n");
374: #endif
375:
376: // Do jump optimization
377: do
378: { flag = FALSE;
379: for (b = startblock; b; b = b->Bnext)
380: { if (b->Bflags & BFLjmpoptdone) /* if no more jmp opts for this blk */
381: continue;
382: i = branch(b,0); // see if jmp => jmp short
383: if (i) /* if any bytes saved */
384: { targ_size_t offset;
385:
386: b->Bsize -= i;
387: offset = b->Boffset + b->Bsize;
388: for (bn = b->Bnext; bn; bn = bn->Bnext)
389: {
390: if (bn->Balign)
391: { targ_size_t u = bn->Balign - 1;
392:
393: offset = (offset + u) & ~u;
394: }
395: bn->Boffset = offset;
396: offset += bn->Bsize;
397: }
398: coffset = offset;
399: flag = TRUE;
400: }
401: }
402: if (!I16 && !(config.flags4 & CFG4optimized))
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
403: break; // use the long conditional jmps
404: } while (flag); // loop till no more bytes saved
405: #ifdef DEBUG
406: debugw && printf("code jump optimization complete\n");
407: #endif
408:
409: #if MARS
410: if (usednteh & NTEH_try)
411: {
412: // Do this before code is emitted because we patch some instructions
413: nteh_filltables();
414: }
415: #endif
416:
417: // Compute starting offset for switch tables
418: #if ELFOBJ || MACHOBJ
419: swoffset = (config.flags & CFGromable) ? coffset : CDoffset;
420: #else
421: swoffset = (config.flags & CFGromable) ? coffset : Doffset;
422: #endif
423: swoffset = align(0,swoffset);
424:
425: // Emit the generated code
426: if (eecontext.EEcompile == 1)
427: {
428: codout(eecontext.EEcode);
429: code_free(eecontext.EEcode);
430: #if SCPP
431: el_free(eecontext.EEelem);
432: #endif
433: }
434: else
435: {
436: for (b = startblock; b; b = b->Bnext)
437: {
438: if (b->BC == BCjmptab || b->BC == BCswitch)
439: { b->Btableoffset = swoffset; /* offset of sw tab */
440: swoffset += b->Btablesize;
441: }
442: jmpaddr(b->Bcode); /* assign jump addresses */
443: #ifdef DEBUG
444: if (debugc)
445: { printf("Boffset = x%lx, Bsize = x%lx, Coffset = x%lx\n",
446: (long)b->Boffset,(long)b->Bsize,(long)Coffset);
447: if (b->Bcode)
448: printf( "First opcode of block is: %0x\n", b->Bcode->Iop );
449: }
450: #endif
451: if (b->Balign)
452: { unsigned u = b->Balign;
453: unsigned nalign = (u - (unsigned)Coffset) & (u - 1);
454:
455: while (nalign--)
456: obj_byte(cseg,Coffset++,0x90); // XCHG AX,AX
457: }
458: assert(b->Boffset == Coffset);
459:
460: #if SCPP
461: if (CPP &&
462: !(config.flags2 & CFG2seh))
463: {
464: //printf("b = %p, index = %d\n",b,b->Bindex);
465: //except_index_set(b->Bindex);
466:
467: if (btry != b->Btry)
468: {
469: btry = b->Btry;
470: except_pair_setoffset(b,Coffset - funcoffset);
471: }
472: if (b->BC == BCtry)
473: {
474: btry = b;
475: except_pair_setoffset(b,Coffset - funcoffset);
476: }
477: }
478: #endif
479: codout(b->Bcode); // output code
480: }
481: if (coffset != Coffset)
482: {
483: #ifdef DEBUG
484: printf("coffset = %ld, Coffset = %ld\n",(long)coffset,(long)Coffset);
485: #endif
486: assert(0);
487: }
488: funcsym_p->Ssize = Coffset - funcoffset; // size of function
489:
490: #if NTEXCEPTIONS || MARS
491: #if (SCPP && NTEXCEPTIONS)
492: if (usednteh & NTEHcpp)
493: #elif MARS
494: if (usednteh & NTEH_try)
495: #endif
496: { assert(!(config.flags & CFGromable));
497: //printf("framehandleroffset = x%x, coffset = x%x\n",framehandleroffset,coffset);
498: reftocodseg(cseg,framehandleroffset,coffset);
499: }
500: #endif
501:
502:
503: // Write out switch tables
504: flag = FALSE; // TRUE if last active block was a ret
505: for (b = startblock; b; b = b->Bnext)
506: {
507: switch (b->BC)
508: { case BCjmptab: /* if jump table */
509: outjmptab(b); /* write out jump table */
510: break;
511: case BCswitch:
512: outswitab(b); /* write out switch table */
513: break;
514: case BCret:
515: case BCretexp:
516: /* Compute offset to return code from start of function */
517: retoffset = b->Boffset + b->Bsize - retsize - funcoffset;
518: #if MARS
519: /* Add 3 bytes to retoffset in case we have an exception
520: * handler. THIS PROBABLY NEEDS TO BE IN ANOTHER SPOT BUT
521: * IT FIXES THE PROBLEM HERE AS WELL.
522: */
523: if (usednteh & NTEH_try)
524: retoffset += 3;
525: #endif
526: flag = TRUE;
527: break;
528: case BCexit:
529: // Fake it to keep debugger happy
530: retoffset = b->Boffset + b->Bsize - funcoffset;
531: break;
532: }
533: }
534: if (flag && configv.addlinenumbers && !(funcsym_p->ty() & mTYnaked))
535: /* put line number at end of function on the
536: start of the last instruction
537: */
538: /* Instead, try offset to cleanup code */
539: objlinnum(funcsym_p->Sfunc->Fendline,funcoffset + retoffset);
540:
541: #if MARS
542: if (usednteh & NTEH_try)
543: {
544: // Do this before code is emitted because we patch some instructions
545: nteh_gentables();
546: }
547: if (usednteh & EHtry)
548: {
549: except_gentables();
550: }
551: #endif
552:
553: #if SCPP
554: #if NTEXCEPTIONS
555: // Write out frame handler
556: if (usednteh & NTEHcpp)
557: nteh_framehandler(except_gentables());
558: else
559: #endif
560: {
561: #if NTEXCEPTIONS
562: if (usednteh & NTEH_try)
563: nteh_gentables();
564: else
565: #endif
566: {
567: if (CPP)
568: except_gentables();
569: }
570: ;
571: }
572: #endif
573: for (b = startblock; b; b = b->Bnext)
574: {
575: code_free(b->Bcode);
576: b->Bcode = NULL;
577: }
578:
579: }
580:
581: // Mask of regs saved
582: // BUG: do interrupt functions save BP?
583: funcsym_p->Sregsaved = (functy == TYifunc) ? mBP : (mfuncreg | fregsaved);
584:
585: util_free(csextab);
586: csextab = NULL;
587: #ifdef DEBUG
588: if (stackused != 0)
589: printf("stackused = %d\n",stackused);
590: #endif
591: assert(stackused == 0); /* nobody in 8087 stack */
592:
593: /* Clean up ndp save array */
594: mem_free(NDP::save);
595: NDP::save = NULL;
596: NDP::savetop = 0;
597: NDP::savemax = 0;
598: }
599:
600:
601: /******************************
602: * Compute offsets for remaining tmp, automatic and register variables
603: * that did not make it into registers.
604: */
605:
606: void stackoffsets(int flags)
607: {
608: symbol *s;
609: targ_size_t Amax,sz;
610: unsigned alignsize;
611: int offi;
warning C4101: 'offi' : unreferenced local variable
612: #if AUTONEST
613: targ_size_t offstack[20];
614: int offi = 0; // index into offstack[]
615: #endif
616: vec_t tbl = NULL;
617:
618:
619: //printf("stackoffsets()\n");
620: if (config.flags4 & CFG4optimized)
621: {
622: tbl = vec_calloc(globsym.top);
623: }
624: Aoffset = 0; // automatic & register offset
625: Toffset = 0; // temporary offset
626: Poffset = 0; // parameter offset
627: EEoffset = 0; // for SCstack's
628: Amax = 0;
629: Aalign = REGSIZE;
630: for (int pass = 0; pass < 2; pass++)
warning C6244: Local declaration of 'pass' hides previous declaration at line '604' of 'c:\projects\extern\d\dmd\src\backend\code.h'
631: {
632: for (int si = 0; si < globsym.top; si++)
633: { s = globsym.tab[si];
634: if (s->Sflags & SFLdead ||
635: (!anyiasm && !(s->Sflags & SFLread) && s->Sflags & SFLunambig &&
636: #if MARS
637: /* mTYvolatile was set if s has been reference by a nested function
638: * meaning we'd better allocate space for it
639: */
640: !(s->Stype->Tty & mTYvolatile) &&
641: #endif
642: (config.flags4 & CFG4optimized || !config.fulltypes))
643: )
644: sz = 0;
645: else
646: { sz = type_size(s->Stype);
647: if (sz == 0)
648: sz++; // can't handle 0 length structs
649: }
650: alignsize = type_alignsize(s->Stype);
651:
652: //printf("symbol '%s', size = x%lx, align = %d, read = %x\n",s->Sident,(long)sz, (int)type_alignsize(s->Stype), s->Sflags & SFLread);
653: assert((int)sz >= 0);
654:
655: if (pass == 1)
656: {
657: if (s->Sclass == SCfastpar) // if parameter s is passed in a register
658: {
659: /* Allocate in second pass in order to get these
660: * right next to the stack frame pointer, EBP.
661: * Needed so we can call nested contract functions
662: * frequire and fensure.
663: */
664: if (s->Sfl == FLreg) // if allocated in register
665: continue;
666: /* Needed because storing fastpar's on the stack in prolog()
667: * does the entire register
668: */
669: if (sz < REGSIZE)
warning C4018: '<' : signed/unsigned mismatch
670: sz = REGSIZE;
671:
672: Aoffset = align(sz,Aoffset);
673: s->Soffset = Aoffset;
674: Aoffset += sz;
675: if (Aoffset > Amax)
676: Amax = Aoffset;
677: //printf("fastpar '%s' sz = %d, auto offset = x%lx\n",s->Sident,sz,(long)s->Soffset);
678:
679: // Align doubles to 8 byte boundary
680: if (!I16 && alignsize > REGSIZE)
warning C4018: '>' : signed/unsigned mismatch
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
681: Aalign = alignsize;
682: }
683: continue;
684: }
685:
686: /* Can't do this for CPP because the inline function expander
687: adds new symbols on the end.
688: */
689: #if AUTONEST
690: /*printf("symbol '%s', push = %d, pop = %d\n",
691: s->Sident,s->Spush,s->Spop);*/
692:
693: /* Can't do this for optimizer if any code motion occurred.
694: Code motion changes the live range, so variables that
695: occupy the same space could have live ranges that overlap!
696: */
697: if (config.flags4 & CFG4optimized)
698: s->Spop = 0;
699: else
700: while (s->Spush != 0)
701: { s->Spush--;
702: assert(offi < arraysize(offstack));
703: /*printf("Pushing offset x%x\n",Aoffset);*/
704: offstack[offi++] = Aoffset;
705: }
706: #endif
707:
708: switch (s->Sclass)
709: {
710: case SCfastpar:
711: break; // ignore on pass 0
712: case SCregister:
713: case SCauto:
714: if (s->Sfl == FLreg) // if allocated in register
715: break;
716: // See if we can share storage with another variable
717: if (config.flags4 & CFG4optimized &&
718: // Don't share because could stomp on variables
719: // used in finally blocks
720: !(usednteh & ~NTEHjmonitor) &&
721: s->Srange && sz && flags && !(s->Sflags & SFLspill))
722: {
723: for (int i = 0; i < si; i++)
724: {
725: if (!vec_testbit(i,tbl))
726: continue;
727: symbol *sp = globsym.tab[i];
728: //printf("auto s = '%s', sp = '%s', %d, %d, %d\n",s->Sident,sp->Sident,dfotop,vec_numbits(s->Srange),vec_numbits(sp->Srange));
729: if (vec_disjoint(s->Srange,sp->Srange) &&
730: sz <= type_size(sp->Stype))
731: {
732: vec_or(sp->Srange,sp->Srange,s->Srange);
733: //printf("sharing space - '%s' onto '%s'\n",s->Sident,sp->Sident);
734: s->Soffset = sp->Soffset;
735: goto L2;
736: }
737: }
738: }
739: Aoffset = align(sz,Aoffset);
740: s->Soffset = Aoffset;
741: //printf("auto '%s' sz = %d, auto offset = x%lx\n",s->Sident,sz,(long)s->Soffset);
742: Aoffset += sz;
743: if (Aoffset > Amax)
744: Amax = Aoffset;
745: if (s->Srange && sz && !(s->Sflags & SFLspill))
746: vec_setbit(si,tbl);
747:
748: // Align doubles to 8 byte boundary
749: if (!I16 && type_alignsize(s->Stype) > REGSIZE)
warning C4018: '>' : signed/unsigned mismatch
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
750: Aalign = type_alignsize(s->Stype);
751: L2:
752: break;
753:
754: case SCtmp:
755: // Allocated separately from SCauto to avoid storage
756: // overlapping problems.
757: Toffset = align(sz,Toffset);
758: s->Soffset = Toffset;
759: //printf("tmp offset = x%lx\n",(long)s->Soffset);
760: Toffset += sz;
761: break;
762:
763: case SCstack:
764: EEoffset = align(sz,EEoffset);
765: s->Soffset = EEoffset;
766: //printf("EEoffset = x%lx\n",(long)s->Soffset);
767: EEoffset += sz;
768: break;
769:
770: case SCparameter:
771: Poffset = align(REGSIZE,Poffset); /* align on word stack boundary */
772: if (I64 && alignsize == 16 && Poffset & 8)
773: Poffset += 8;
774: s->Soffset = Poffset;
775: //printf("%s param offset = x%lx, alignsize = %d\n",s->Sident,(long)s->Soffset, (int)alignsize);
776: Poffset += (s->Sflags & SFLdouble)
777: ? type_size(tsdouble) // float passed as double
778: : type_size(s->Stype);
779: break;
780: case SCpseudo:
781: case SCstatic:
782: case SCbprel:
783: break;
784: default:
785: #ifdef DEBUG
786: symbol_print(s);
787: #endif
788: assert(0);
789: }
790:
791: #if AUTONEST
792: while (s->Spop != 0)
793: { s->Spop--;
794: assert(offi > 0);
795: Aoffset = offstack[--offi];
796: /*printf("Popping offset x%x\n",Aoffset);*/
797: }
798: #endif
799: }
800: }
801: Aoffset = Amax;
802: Aoffset = align(0,Aoffset);
803: if (Aalign > REGSIZE)
804: Aoffset = (Aoffset + Aalign - 1) & ~(Aalign - 1);
805: //printf("Aligned Aoffset = x%lx, Toffset = x%lx\n", (long)Aoffset,(long)Toffset);
806: Toffset = align(0,Toffset);
807:
808: if (config.flags4 & CFG4optimized)
809: {
810: vec_free(tbl);
811: }
812: }
813:
814: /****************************
815: * Generate code for a block.
816: */
817:
818: STATIC void blcodgen(block *bl)
819: { regm_t retregs;
820: bool jcond;
821: elem *e;
822: code *c;
823: block *nextb;
824: block *bs1,*bs2;
825: list_t bpl;
826: int refparamsave;
827: regm_t mfuncregsave = mfuncreg;
828: char *sflsave = NULL;
829: int anyspill;
830:
831: //dbg_printf("blcodgen(%p)\n",bl);
832:
833: /* Determine existing immediate values in registers by ANDing
834: together the values from all the predecessors of b.
835: */
836: assert(bl->Bregcon.immed.mval == 0);
837: regcon.immed.mval = 0; // assume no previous contents in registers
838: // regcon.cse.mval = 0;
839: for (bpl = bl->Bpred; bpl; bpl = list_next(bpl))
840: { block *bp = list_block(bpl);
841:
842: if (bpl == bl->Bpred)
843: { regcon.immed = bp->Bregcon.immed;
844: regcon.params = bp->Bregcon.params;
845: // regcon.cse = bp->Bregcon.cse;
846: }
847: else
848: { int i;
849:
850: regcon.params &= bp->Bregcon.params;
851: if ((regcon.immed.mval &= bp->Bregcon.immed.mval) != 0)
852: // Actual values must match, too
853: for (i = 0; i < REGMAX; i++)
854: {
855: if (regcon.immed.value[i] != bp->Bregcon.immed.value[i])
856: regcon.immed.mval &= ~mask[i];
857: }
858: #if 0
859: if ((regcon.cse.mval &= bp->Bregcon.cse.mval) != 0)
860: // Actual values must match, too
861: for (i = 0; i < REGMAX; i++)
862: {
863: if (regcon.cse.value[i] != bp->Bregcon.cse.value[i])
864: regcon.cse.mval &= ~mask[i];
865: }
866: #endif
867: }
868: }
869: regcon.cse.mops &= regcon.cse.mval;
870:
871: // Set regcon.mvar according to what variables are in registers for this block
872: c = NULL;
873: regcon.mvar = 0;
874: regcon.mpvar = 0;
875: regcon.indexregs = 1;
876: anyspill = 0;
877: if (config.flags4 & CFG4optimized)
878: { SYMIDX i;
879: code *cload = NULL;
880: code *cstore = NULL;
881:
882: sflsave = (char *) alloca(globsym.top * sizeof(char));
warning C6255: _alloca indicates failure by raising a stack overflow exception. Consider using _malloca instead
883: for (i = 0; i < globsym.top; i++)
884: { symbol *s = globsym.tab[i];
885:
886: sflsave[i] = s->Sfl;
887: if (s->Sclass & SCfastpar &&
888: regcon.params & mask[s->Spreg] &&
889: vec_testbit(dfoidx,s->Srange))
890: {
891: regcon.used |= mask[s->Spreg];
892: }
893:
894: if (s->Sfl == FLreg)
895: { if (vec_testbit(dfoidx,s->Srange))
896: { regcon.mvar |= s->Sregm;
897: if (s->Sclass == SCfastpar)
898: regcon.mpvar |= s->Sregm;
899: }
900: }
901: else if (s->Sflags & SFLspill)
902: { if (vec_testbit(dfoidx,s->Srange))
903: {
904: anyspill = i + 1;
905: cgreg_spillreg_prolog(bl,s,&cstore,&cload);
906: if (vec_testbit(dfoidx,s->Slvreg))
907: { s->Sfl = FLreg;
908: regcon.mvar |= s->Sregm;
909: regcon.cse.mval &= ~s->Sregm;
910: regcon.immed.mval &= ~s->Sregm;
911: if (s->Sclass == SCfastpar)
912: regcon.mpvar |= s->Sregm;
913: }
914: }
915: }
916: }
917: if ((regcon.cse.mops & regcon.cse.mval) != regcon.cse.mops)
918: { code *cx;
919:
920: cx = cse_save(regcon.cse.mops & ~regcon.cse.mval);
921: cstore = cat(cx, cstore);
922: }
923: c = cat(cstore,cload);
924: mfuncreg &= ~regcon.mvar; // use these registers
925: regcon.used |= regcon.mvar;
926:
927: // Determine if we have more than 1 uncommitted index register
928: regcon.indexregs = IDXREGS & ~regcon.mvar;
929: regcon.indexregs &= regcon.indexregs - 1;
930: }
931:
932: e = bl->Belem;
933: regsave.idx = 0;
934: retregs = 0;
935: reflocal = 0;
936: refparamsave = refparam;
937: refparam = 0;
938: assert((regcon.cse.mops & regcon.cse.mval) == regcon.cse.mops);
939: switch (bl->BC) /* block exit condition */
940: {
941: case BCiftrue:
942: jcond = TRUE;
943: bs1 = list_block(bl->Bsucc);
944: bs2 = list_block(list_next(bl->Bsucc));
945: if (bs1 == bl->Bnext)
946: { // Swap bs1 and bs2
947: block *btmp;
948:
949: jcond ^= 1;
950: btmp = bs1;
951: bs1 = bs2;
952: bs2 = btmp;
953: }
954: c = cat(c,logexp(e,jcond,FLblock,(code *) bs1));
955: nextb = bs2;
956: bl->Bcode = NULL;
957: L2:
958: if (nextb != bl->Bnext)
959: { if (configv.addlinenumbers && bl->Bsrcpos.Slinnum &&
960: !(funcsym_p->ty() & mTYnaked))
961: cgen_linnum(&c,bl->Bsrcpos);
962: assert(!(bl->Bflags & BFLepilog));
963: c = cat(c,genjmp(CNIL,JMP,FLblock,nextb));
964: }
965: bl->Bcode = cat(bl->Bcode,c);
966: break;
967: case BCjmptab:
968: case BCifthen:
969: case BCswitch:
970: assert(!(bl->Bflags & BFLepilog));
971: doswitch(bl); /* hide messy details */
972: bl->Bcode = cat(c,bl->Bcode);
973: break;
974: #if MARS
975: case BCjcatch:
976: // Mark all registers as destroyed. This will prevent
977: // register assignments to variables used in catch blocks.
978: c = cat(c,getregs((I32 | I64) ? allregs : (ALLREGS | mES)));
979: #if 0 && TARGET_LINUX
980: if (config.flags3 & CFG3pic && !(allregs & mBX))
981: {
982: c = cat(c, cod3_load_got());
983: }
984: #endif
985: goto case_goto;
986: #endif
987: #if SCPP
988: case BCcatch:
989: // Mark all registers as destroyed. This will prevent
990: // register assignments to variables used in catch blocks.
991: c = cat(c,getregs(allregs | mES));
992: #if 0 && TARGET_LINUX
993: if (config.flags3 & CFG3pic && !(allregs & mBX))
994: {
995: c = cat(c, cod3_load_got());
996: }
997: #endif
998: goto case_goto;
999:
1000: case BCtry:
1001: usednteh |= EHtry;
1002: if (config.flags2 & CFG2seh)
1003: usednteh |= NTEHtry;
1004: goto case_goto;
1005: #endif
1006: case BCgoto:
1007: nextb = list_block(bl->Bsucc);
1008: if ((funcsym_p->Sfunc->Fflags3 & Fnteh ||
1009: (MARS /*&& config.flags2 & CFG2seh*/)) &&
1010: bl->Btry != nextb->Btry &&
1011: nextb->BC != BC_finally)
1012: { int toindex;
1013: int fromindex;
1014:
1015: bl->Bcode = NULL;
1016: c = gencodelem(c,e,&retregs,TRUE);
1017: toindex = nextb->Btry ? nextb->Btry->Bscope_index : -1;
1018: assert(bl->Btry);
1019: fromindex = bl->Btry->Bscope_index;
1020: #if MARS
1021: if (toindex + 1 == fromindex)
1022: { // Simply call __finally
1023: if (bl->Btry &&
1024: list_block(list_next(bl->Btry->Bsucc))->BC == BCjcatch)
1025: {
1026: goto L2;
1027: }
1028: }
1029: #endif
1030: if (config.flags2 & CFG2seh)
1031: c = cat(c,nteh_unwind(0,toindex));
1032: #if MARS && (TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS)
1033: else if (toindex + 1 <= fromindex)
1034: {
1035: //c = cat(c, linux_unwind(0, toindex));
1036: block *bt;
1037:
1038: //printf("B%d: fromindex = %d, toindex = %d\n", bl->Bdfoidx, fromindex, toindex);
1039: bt = bl;
1040: while ((bt = bt->Btry) != NULL && bt->Bscope_index != toindex)
1041: { block *bf;
1042:
1043: //printf("\tbt->Bscope_index = %d, bt->Blast_index = %d\n", bt->Bscope_index, bt->Blast_index);
1044: bf = list_block(list_next(bt->Bsucc));
1045: // Only look at try-finally blocks
1046: if (bf->BC == BCjcatch)
1047: continue;
1048:
1049: if (bf == nextb)
1050: continue;
1051: //printf("\tbf = B%d, nextb = B%d\n", bf->Bdfoidx, nextb->Bdfoidx);
1052: if (nextb->BC == BCgoto &&
1053: !nextb->Belem &&
1054: bf == list_block(nextb->Bsucc))
1055: continue;
1056:
1057: // call __finally
1058: code *cs;
1059: code *cr;
1060: int nalign = 0;
1061:
1062: gensaverestore(retregs,&cs,&cr);
1063: if (STACKALIGN == 16)
1064: { int npush = (numbitsset(retregs) + 1) * REGSIZE;
1065: if (npush & (STACKALIGN - 1))
1066: { nalign = STACKALIGN - (npush & (STACKALIGN - 1));
1067: cs = genc2(cs,0x81,modregrm(3,5,SP),nalign); // SUB ESP,nalign
1068: if (I64)
1069: code_orrex(cs, REX_W);
1070: }
1071: }
1072: cs = genc(cs,0xE8,0,0,0,FLblock,(long)list_block(bf->Bsucc));
1073: if (nalign)
1074: { cs = genc2(cs,0x81,modregrm(3,0,SP),nalign); // ADD ESP,nalign
1075: if (I64)
1076: code_orrex(cs, REX_W);
1077: }
1078: c = cat3(c,cs,cr);
1079: }
1080: }
1081: #endif
1082: goto L2;
1083: }
1084: case_goto:
1085: c = gencodelem(c,e,&retregs,TRUE);
1086: if (anyspill)
1087: { // Add in the epilog code
1088: code *cstore = NULL;
1089: code *cload = NULL;
1090:
1091: for (int i = 0; i < anyspill; i++)
1092: { symbol *s = globsym.tab[i];
1093:
1094: if (s->Sflags & SFLspill &&
1095: vec_testbit(dfoidx,s->Srange))
1096: {
1097: s->Sfl = sflsave[i]; // undo block register assignments
1098: cgreg_spillreg_epilog(bl,s,&cstore,&cload);
1099: }
1100: }
1101: c = cat3(c,cstore,cload);
1102: }
1103:
1104: L3:
1105: bl->Bcode = NULL;
1106: nextb = list_block(bl->Bsucc);
1107: goto L2;
1108:
1109: case BC_try:
1110: if (config.flags2 & CFG2seh)
1111: { usednteh |= NTEH_try;
1112: nteh_usevars();
1113: }
1114: else
1115: usednteh |= EHtry;
1116: goto case_goto;
1117:
1118: case BC_finally:
1119: // Mark all registers as destroyed. This will prevent
1120: // register assignments to variables used in finally blocks.
1121: assert(!getregs(allregs));
1122: assert(!e);
1123: assert(!bl->Bcode);
1124: #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
1125: if (config.flags3 & CFG3pic)
1126: {
1127: int nalign = 0;
1128: if (STACKALIGN == 16)
1129: { nalign = STACKALIGN - REGSIZE;
1130: c = genc2(c,0x81,modregrm(3,5,SP),nalign); // SUB ESP,nalign
1131: if (I64)
1132: code_orrex(c, REX_W);
1133: }
1134: // CALL bl->Bsucc
1135: c = genc(c,0xE8,0,0,0,FLblock,(long)list_block(bl->Bsucc));
1136: if (nalign)
1137: { c = genc2(c,0x81,modregrm(3,0,SP),nalign); // ADD ESP,nalign
1138: if (I64)
1139: code_orrex(c, REX_W);
1140: }
1141: // JMP list_next(bl->Bsucc)
1142: nextb = list_block(list_next(bl->Bsucc));
1143: goto L2;
1144: }
1145: else
1146: #endif
1147: {
1148: // Generate a PUSH of the address of the successor to the
1149: // corresponding BC_ret
1150: //assert(list_block(list_next(bl->Bsucc))->BC == BC_ret);
1151: // PUSH &succ
1152: c = genc(c,0x68,0,0,0,FLblock,(long)list_block(list_next(bl->Bsucc)));
1153: nextb = list_block(bl->Bsucc);
1154: goto L2;
1155: }
1156:
1157: case BC_ret:
1158: c = gencodelem(c,e,&retregs,TRUE);
1159: bl->Bcode = gen1(c,0xC3); // RET
1160: break;
1161:
1162: #if NTEXCEPTIONS
1163: case BC_except:
1164: assert(!e);
1165: usednteh |= NTEH_except;
1166: c = cat(c,nteh_setsp(0x8B));
1167: getregs(allregs);
1168: goto L3;
1169:
1170: case BC_filter:
1171: c = cat(c,nteh_filter(bl));
1172: // Mark all registers as destroyed. This will prevent
1173: // register assignments to variables used in filter blocks.
1174: getregs(allregs);
1175: retregs = regmask(e->Ety, TYnfunc);
1176: c = gencodelem(c,e,&retregs,TRUE);
1177: bl->Bcode = gen1(c,0xC3); // RET
1178: break;
1179: #endif
1180:
1181: case BCretexp:
1182: retregs = regmask(e->Ety, funcsym_p->ty());
1183:
1184: // For the final load into the return regs, don't set regcon.used,
1185: // so that the optimizer can potentially use retregs for register
1186: // variable assignments.
1187:
1188: if (config.flags4 & CFG4optimized)
1189: { regm_t usedsave;
1190:
1191: c = cat(c,docommas(&e));
1192: usedsave = regcon.used;
1193: if (EOP(e))
1194: c = gencodelem(c,e,&retregs,TRUE);
1195: else
1196: {
1197: if (e->Eoper == OPconst)
1198: regcon.mvar = 0;
1199: c = gencodelem(c,e,&retregs,TRUE);
1200: regcon.used = usedsave;
1201: if (e->Eoper == OPvar)
1202: { symbol *s = e->EV.sp.Vsym;
1203:
1204: if (s->Sfl == FLreg && s->Sregm != mAX)
1205: retsym = s;
1206: }
1207: }
1208: }
1209: else
1210: {
1211: case BCret:
1212: case BCexit:
1213: c = gencodelem(c,e,&retregs,TRUE);
1214: }
1215: bl->Bcode = c;
1216: if (retregs == mST0)
1217: { assert(stackused == 1);
1218: pop87(); // account for return value
1219: }
1220: else if (retregs == mST01)
1221: { assert(stackused == 2);
1222: pop87();
1223: pop87(); // account for return value
1224: }
1225: if (bl->BC == BCexit && config.flags4 & CFG4optimized)
1226: mfuncreg = mfuncregsave;
1227: if (MARS || usednteh & NTEH_try)
1228: { block *bt;
1229:
1230: bt = bl;
1231: while ((bt = bt->Btry) != NULL)
1232: { block *bf;
1233:
1234: bf = list_block(list_next(bt->Bsucc));
1235: #if MARS
1236: // Only look at try-finally blocks
1237: if (bf->BC == BCjcatch)
1238: {
1239: continue;
1240: }
1241: #endif
1242: if (config.flags2 & CFG2seh)
1243: {
1244: if (bt->Bscope_index == 0)
1245: {
1246: // call __finally
1247: code *cs;
1248: code *cr;
1249:
1250: c = cat(c,nteh_gensindex(-1));
1251: gensaverestore(retregs,&cs,&cr);
1252: cs = genc(cs,0xE8,0,0,0,FLblock,(long)list_block(bf->Bsucc));
1253: bl->Bcode = cat3(c,cs,cr);
1254: }
1255: else
1256: bl->Bcode = cat(c,nteh_unwind(retregs,~0));
1257: break;
1258: }
1259: else
1260: {
1261: // call __finally
1262: code *cs;
1263: code *cr;
1264: int nalign = 0;
1265:
1266: gensaverestore(retregs,&cs,&cr);
1267: if (STACKALIGN == 16)
1268: { int npush = (numbitsset(retregs) + 1) * REGSIZE;
1269: if (npush & (STACKALIGN - 1))
1270: { nalign = STACKALIGN - (npush & (STACKALIGN - 1));
1271: cs = genc2(cs,0x81,modregrm(3,5,SP),nalign); // SUB ESP,nalign
1272: if (I64)
1273: code_orrex(cs, REX_W);
1274: }
1275: }
1276: // CALL bf->Bsucc
1277: cs = genc(cs,0xE8,0,0,0,FLblock,(long)list_block(bf->Bsucc));
1278: if (nalign)
1279: { cs = genc2(cs,0x81,modregrm(3,0,SP),nalign); // ADD ESP,nalign
1280: if (I64)
1281: code_orrex(cs, REX_W);
1282: }
1283: bl->Bcode = c = cat3(c,cs,cr);
1284: }
1285: }
1286: }
1287: break;
1288:
1289: #if SCPP || MARS
1290: case BCasm:
1291: assert(!e);
1292: // Mark destroyed registers
1293: assert(!c);
1294: c = cat(c,getregs(iasm_regs(bl)));
1295: if (bl->Bsucc)
1296: { nextb = list_block(bl->Bsucc);
1297: if (!bl->Bnext)
1298: goto L2;
1299: if (nextb != bl->Bnext &&
1300: bl->Bnext &&
1301: !(bl->Bnext->BC == BCgoto &&
1302: !bl->Bnext->Belem &&
1303: nextb == list_block(bl->Bnext->Bsucc)))
1304: { code *cl;
1305:
1306: // See if already have JMP at end of block
1307: cl = code_last(bl->Bcode);
1308: if (!cl || cl->Iop != JMP)
1309: goto L2; // add JMP at end of block
1310: }
1311: }
1312: break;
1313: #endif
1314: default:
1315: #ifdef DEBUG
1316: printf("bl->BC = %d\n",bl->BC);
1317: #endif
1318: assert(0);
1319: }
1320:
1321: for (int i = 0; i < anyspill; i++)
1322: { symbol *s = globsym.tab[i];
1323:
1324: s->Sfl = sflsave[i]; // undo block register assignments
1325: }
1326:
1327: if (reflocal)
1328: bl->Bflags |= BFLreflocal;
1329: if (refparam)
1330: bl->Bflags |= BFLrefparam;
1331: refparam |= refparamsave;
1332: bl->Bregcon.immed = regcon.immed;
1333: bl->Bregcon.cse = regcon.cse;
1334: bl->Bregcon.used = regcon.used;
1335: bl->Bregcon.params = regcon.params;
1336: #ifdef DEBUG
1337: debugw && printf("code gen complete\n");
1338: #endif
1339: }
1340:
1341: /*****************************************
1342: * Add in exception handling code.
1343: */
1344:
1345: #if SCPP
1346:
1347: STATIC void cgcod_eh()
1348: { block *btry;
1349: code *c;
1350: code *c1;
1351: list_t stack;
1352: list_t list;
1353: block *b;
1354: int idx;
1355: int lastidx;
1356: int tryidx;
1357: int i;
1358:
1359: if (!(usednteh & (EHtry | EHcleanup)))
1360: return;
1361:
1362: // Compute Bindex for each block
1363: for (b = startblock; b; b = b->Bnext)
1364: { b->Bindex = -1;
1365: b->Bflags &= ~BFLvisited; /* mark as unvisited */
1366: }
1367: btry = NULL;
1368: lastidx = 0;
1369: startblock->Bindex = 0;
1370: for (b = startblock; b; b = b->Bnext)
1371: {
1372: if (btry == b->Btry && b->BC == BCcatch) // if don't need to pop try block
1373: { block *br;
1374:
1375: br = list_block(b->Bpred); // find corresponding try block
1376: assert(br->BC == BCtry);
1377: b->Bindex = br->Bindex;
1378: }
1379: else if (btry != b->Btry && b->BC != BCcatch ||
1380: !(b->Bflags & BFLvisited))
1381: b->Bindex = lastidx;
1382: b->Bflags |= BFLvisited;
1383: #ifdef DEBUG
1384: if (debuge)
1385: {
1386: WRBC(b->BC);
1387: dbg_printf(" block (%p) Btry=%p Bindex=%d\n",b,b->Btry,b->Bindex);
1388: }
1389: #endif
1390: except_index_set(b->Bindex);
1391: if (btry != b->Btry) // exited previous try block
1392: {
1393: except_pop(b,NULL,btry);
1394: btry = b->Btry;
1395: }
1396: if (b->BC == BCtry)
1397: {
1398: except_push(b,NULL,b);
1399: btry = b;
1400: tryidx = except_index_get();
1401: b->Bcode = cat(nteh_gensindex(tryidx - 1),b->Bcode);
1402: }
1403:
1404: stack = NULL;
1405: for (c = b->Bcode; c; c = code_next(c))
1406: {
1407: if ((c->Iop & 0xFF) == ESCAPE)
1408: {
1409: c1 = NULL;
1410: switch (c->Iop & 0xFFFF00)
1411: {
1412: case ESCctor:
1413: //printf("ESCctor\n");
1414: except_push(c,c->IEV1.Vtor,NULL);
1415: goto L1;
1416:
1417: case ESCdtor:
1418: //printf("ESCdtor\n");
1419: except_pop(c,c->IEV1.Vtor,NULL);
1420: L1: if (config.flags2 & CFG2seh)
1421: {
1422: c1 = nteh_gensindex(except_index_get() - 1);
1423: code_next(c1) = code_next(c);
1424: code_next(c) = c1;
1425: }
1426: break;
1427: case ESCmark:
1428: //printf("ESCmark\n");
1429: idx = except_index_get();
1430: list_prependdata(&stack,idx);
1431: except_mark();
1432: break;
1433: case ESCrelease:
1434: //printf("ESCrelease\n");
1435: idx = list_data(stack);
1436: list_pop(&stack);
1437: if (idx != except_index_get())
1438: {
1439: if (config.flags2 & CFG2seh)
1440: { c1 = nteh_gensindex(idx - 1);
1441: code_next(c1) = code_next(c);
1442: code_next(c) = c1;
1443: }
1444: else
1445: { except_pair_append(c,idx - 1);
1446: c->Iop = ESCAPE | ESCoffset;
1447: }
1448: }
1449: except_release();
1450: break;
1451: case ESCmark2:
1452: //printf("ESCmark2\n");
1453: except_mark();
1454: break;
1455: case ESCrelease2:
1456: //printf("ESCrelease2\n");
1457: except_release();
1458: break;
1459: }
1460: }
1461: }
1462: assert(stack == NULL);
1463: b->Bendindex = except_index_get();
1464:
1465: if (b->BC != BCret && b->BC != BCretexp)
1466: lastidx = b->Bendindex;
1467:
1468: // Set starting index for each of the successors
1469: i = 0;
1470: for (list = b->Bsucc; list; list = list_next(list))
1471: { block *bs = list_block(list);
1472:
1473: if (b->BC == BCtry)
1474: { switch (i)
1475: { case 0: // block after catches
1476: bs->Bindex = b->Bendindex;
1477: break;
1478: case 1: // 1st catch block
1479: bs->Bindex = tryidx;
1480: break;
1481: default: // subsequent catch blocks
1482: bs->Bindex = b->Bindex;
1483: break;
1484: }
1485: #ifdef DEBUG
1486: if (debuge)
1487: {
1488: dbg_printf(" 1setting %p to %d\n",bs,bs->Bindex);
1489: }
1490: #endif
1491: }
1492: else if (!(bs->Bflags & BFLvisited))
1493: {
1494: bs->Bindex = b->Bendindex;
1495: #ifdef DEBUG
1496: if (debuge)
1497: {
1498: dbg_printf(" 2setting %p to %d\n",bs,bs->Bindex);
1499: }
1500: #endif
1501: }
1502: bs->Bflags |= BFLvisited;
1503: i++;
1504: }
1505: }
1506:
1507: if (config.flags2 & CFG2seh)
1508: for (b = startblock; b; b = b->Bnext)
1509: {
1510: if (/*!b->Bcount ||*/ b->BC == BCtry)
1511: continue;
1512: for (list = b->Bpred; list; list = list_next(list))
1513: { int pi;
1514:
1515: pi = list_block(list)->Bendindex;
1516: if (b->Bindex != pi)
1517: {
1518: b->Bcode = cat(nteh_gensindex(b->Bindex - 1),b->Bcode);
1519: break;
1520: }
1521: }
1522: }
1523: }
1524:
1525: #endif
1526:
1527: /*****************************
1528: * Given a type, return a mask of
1529: * registers to hold that type.
1530: * Input:
1531: * tyf function type
1532: */
1533:
1534: regm_t regmask(tym_t tym, tym_t tyf)
1535: {
1536: switch (tybasic(tym))
1537: {
1538: case TYvoid:
1539: case TYstruct:
1540: return 0;
1541: case TYbool:
1542: case TYwchar_t:
1543: case TYchar16:
1544: case TYchar:
1545: case TYschar:
1546: case TYuchar:
1547: case TYshort:
1548: case TYushort:
1549: case TYint:
1550: case TYuint:
1551: #if JHANDLE
1552: case TYjhandle:
1553: #endif
1554: case TYnullptr:
1555: case TYnptr:
1556: case TYsptr:
1557: case TYcptr:
1558: return mAX;
1559:
1560: case TYfloat:
1561: case TYifloat:
1562: if (I64)
1563: return mXMM0;
1564: if (config.exe & EX_flat)
1565: return mST0;
1566: case TYlong:
1567: case TYulong:
1568: case TYdchar:
1569: if (!I16)
1570: return mAX;
1571: case TYfptr:
1572: case TYhptr:
1573: return mDX | mAX;
1574:
1575: case TYcent:
1576: case TYucent:
1577: assert(I64);
1578: return mDX | mAX;
1579:
1580: case TYvptr:
1581: return mDX | mBX;
1582:
1583: case TYdouble:
1584: case TYdouble_alias:
1585: case TYidouble:
1586: if (I64)
1587: return mXMM0;
1588: if (config.exe & EX_flat)
1589: return mST0;
1590: return DOUBLEREGS;
1591:
1592: case TYllong:
1593: case TYullong:
1594: return I64 ? mAX : (I32 ? mDX | mAX : DOUBLEREGS);
1595:
1596: case TYldouble:
1597: case TYildouble:
1598: return mST0;
1599:
1600: case TYcfloat:
1601: #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
1602: if (I32 && tybasic(tyf) == TYnfunc)
1603: return mDX | mAX;
1604: #endif
1605: case TYcdouble:
1606: if (I64)
1607: return mXMM0 | mXMM1;
1608: case TYcldouble:
1609: return mST01;
1610:
1611: default:
1612: #if DEBUG
1613: WRTYxx(tym);
1614: #endif
1615: assert(0);
1616: return 0;
1617: }
1618: }
1619:
1620: /******************************
1621: * Count the number of bits set in a register mask.
1622: */
1623:
1624: int numbitsset(regm_t regm)
1625: { int n;
1626:
1627: n = 0;
1628: if (regm)
1629: do
1630: n++;
1631: while ((regm &= regm - 1) != 0);
1632: return n;
1633: }
1634:
1635: /******************************
1636: * Given a register mask, find and return the number
1637: * of the first register that fits.
1638: */
1639:
1640: #undef findreg
1641:
1642: unsigned findreg(regm_t regm
1643: #ifdef DEBUG
1644: ,int line,const char *file
1645: #endif
1646: )
1647: #ifdef DEBUG
1648: #define findreg(regm) findreg((regm),__LINE__,__FILE__)
1649: #endif
1650: {
1651: #ifdef DEBUG
1652: regm_t regmsave = regm;
1653: #endif
1654: int i = 0;
1655: while (1)
1656: {
1657: if (!(regm & 0xF))
1658: {
1659: regm >>= 4;
1660: i += 4;
1661: if (!regm)
1662: break;
1663: }
1664: if (regm & 1)
1665: return i;
1666: regm >>= 1;
1667: i++;
1668: }
1669: #ifdef DEBUG
1670: printf("findreg(x%x, line=%d, file='%s')\n",regmsave,line,file);
1671: fflush(stdout);
1672: #endif
1673: //*(char*)0=0;
1674: assert(0);
1675: return 0;
1676: }
1677:
1678: /***************
1679: * Free element (but not it's leaves! (assume they are already freed))
1680: * Don't decrement Ecount! This is so we can detect if the common subexp
1681: * has already been evaluated.
1682: * If common subexpression is not required anymore, eliminate
1683: * references to it.
1684: */
1685:
1686: void freenode(elem *e)
1687: { unsigned i;
1688:
1689: elem_debug(e);
1690: //dbg_printf("freenode(%p) : comsub = %d, count = %d\n",e,e->Ecomsub,e->Ecount);
1691: if (e->Ecomsub--) return; /* usage count */
1692: if (e->Ecount) /* if it was a CSE */
1693: { for (i = 0; i < arraysize(regcon.cse.value); i++)
1694: { if (regcon.cse.value[i] == e) /* if a register is holding it */
1695: { regcon.cse.mval &= ~mask[i];
1696: regcon.cse.mops &= ~mask[i]; /* free masks */
1697: }
1698: }
1699: for (i = 0; i < cstop; i++)
1700: { if (csextab[i].e == e)
1701: csextab[i].e = NULL;
1702: }
1703: }
1704: }
1705:
1706: /*********************************
1707: * Reset Ecomsub for all elem nodes, i.e. reverse the effects of freenode().
1708: */
1709:
1710: STATIC void resetEcomsub(elem *e)
1711: { unsigned op;
1712:
1713: while (1)
1714: {
1715: elem_debug(e);
1716: e->Ecomsub = e->Ecount;
1717: op = e->Eoper;
1718: if (!OTleaf(op))
1719: { if (OTbinary(op))
1720: resetEcomsub(e->E2);
1721: e = e->E1;
1722: }
1723: else
1724: break;
1725: }
1726: }
1727:
1728: /*********************************
1729: * Determine if elem e is a register variable.
1730: * If so:
1731: * *pregm = mask of registers that make up the variable
1732: * *preg = the least significant register
1733: * returns TRUE
1734: * Else
1735: * returns FALSE
1736: */
1737:
1738: int isregvar(elem *e,regm_t *pregm,unsigned *preg)
1739: { symbol *s;
1740: unsigned u;
warning C4101: 'u' : unreferenced local variable
1741: regm_t m;
warning C4101: 'm' : unreferenced local variable
1742: regm_t regm;
1743: unsigned reg;
1744:
1745: elem_debug(e);
1746: if (e->Eoper == OPvar || e->Eoper == OPrelconst)
1747: {
1748: s = e->EV.sp.Vsym;
1749: switch (s->Sfl)
1750: { case FLreg:
1751: if (s->Sclass == SCparameter)
1752: { refparam = TRUE;
1753: reflocal = TRUE;
1754: }
1755: reg = s->Sreglsw;
1756: regm = s->Sregm;
1757: //assert(tyreg(s->ty()));
1758: #if 0
1759: // Let's just see if there is a CSE in a reg we can use
1760: // instead. This helps avoid AGI's.
1761: if (e->Ecount && e->Ecount != e->Ecomsub)
1762: { int i;
1763:
1764: for (i = 0; i < arraysize(regcon.cse.value); i++)
1765: {
1766: if (regcon.cse.value[i] == e)
1767: { reg = i;
1768: break;
1769: }
1770: }
1771: }
1772: #endif
1773: assert(regm & regcon.mvar && !(regm & ~regcon.mvar));
1774: goto Lreg;
1775:
1776: case FLpseudo:
1777: #if MARS
1778: assert(0);
1779: #else
1780: u = s->Sreglsw;
1781: m = pseudomask[u];
1782: if (m & ALLREGS && (u & ~3) != 4) // if not BP,SP,EBP,ESP,or ?H
1783: { reg = pseudoreg[u] & 7;
1784: regm = m;
1785: goto Lreg;
1786: }
1787: #endif
1788: break;
1789: }
1790: }
1791: return FALSE;
1792:
1793: Lreg:
1794: if (preg)
1795: *preg = reg;
1796: if (pregm)
1797: *pregm = regm;
1798: return TRUE;
1799: }
1800:
1801: /*********************************
1802: * Allocate some registers.
1803: * Input:
1804: * pretregs Pointer to mask of registers to make selection from.
1805: * tym Mask of type we will store in registers.
1806: * Output:
1807: * *pretregs Mask of allocated registers.
1808: * *preg Register number of first allocated register.
1809: * msavereg,mfuncreg retregs bits are cleared.
1810: * regcon.cse.mval,regcon.cse.mops updated
1811: * Returns:
1812: * pointer to code generated if necessary to save any regcon.cse.mops on the
1813: * stack.
1814: */
1815:
1816: #undef allocreg
1817:
1818: code *allocreg(regm_t *pretregs,unsigned *preg,tym_t tym
1819: #ifdef DEBUG
1820: ,int line,const char *file
1821: #endif
1822: )
1823: #ifdef DEBUG
1824: #define allocreg(a,b,c) allocreg((a),(b),(c),__LINE__,__FILE__)
1825: #endif
1826: { regm_t r;
1827: regm_t retregs;
1828: unsigned reg;
1829: unsigned msreg,lsreg;
1830: int count;
1831: unsigned size;
1832:
1833: #if 0
1834: if (pass == PASSfinal)
1835: { dbg_printf("allocreg %s,%d: regcon.mvar %s regcon.cse.mval %s msavereg %s *pretregs %s tym ",
1836: file,line,regm_str(regcon.mvar),regm_str(regcon.cse.mval),
1837: regm_str(msavereg),regm_str(*pretregs));
1838: WRTYxx(tym);
1839: dbg_printf("\n");
1840: }
1841: #endif
1842: tym = tybasic(tym);
1843: size = tysize[tym];
1844: *pretregs &= mES | allregs | XMMREGS;
1845: retregs = *pretregs;
1846: if ((retregs & regcon.mvar) == retregs) // if exactly in reg vars
1847: {
1848: if (size <= REGSIZE)
warning C4018: '<=' : signed/unsigned mismatch
1849: { *preg = findreg(retregs);
1850: assert(retregs == mask[*preg]); /* no more bits are set */
1851: }
1852: else if (size <= 2 * REGSIZE)
warning C4018: '<=' : signed/unsigned mismatch
1853: { *preg = findregmsw(retregs);
1854: assert(retregs & mLSW);
1855: }
1856: else
1857: assert(0);
1858: return getregs(retregs);
1859: }
1860: count = 0;
1861: L1:
1862: //printf("L1: allregs = x%x, *pretregs = x%x\n", allregs, *pretregs);
1863: assert(++count < 20); /* fail instead of hanging if blocked */
1864: assert(retregs);
1865: msreg = lsreg = (unsigned)-1; /* no value assigned yet */
1866: L3:
1867: //printf("L2: allregs = x%x, *pretregs = x%x\n", allregs, *pretregs);
1868: r = retregs & ~(msavereg | regcon.cse.mval | regcon.params);
1869: if (!r)
1870: {
1871: r = retregs & ~(msavereg | regcon.cse.mval);
1872: if (!r)
1873: {
1874: r = retregs & ~(msavereg | regcon.cse.mops);
1875: if (!r)
1876: { r = retregs & ~msavereg;
1877: if (!r)
1878: r = retregs;
1879: }
1880: }
1881: }
1882: if (0 && r & ~fregsaved)
1883: r &= ~fregsaved;
1884:
1885: if (size <= REGSIZE)
warning C4018: '<=' : signed/unsigned mismatch
1886: {
1887: if (r & ~mBP)
1888: r &= ~mBP;
1889:
1890: // If only one index register, prefer to not use LSW registers
1891: if (!regcon.indexregs && r & ~mLSW)
1892: r &= ~mLSW;
1893:
1894: if (pass == PASSfinal && r & ~lastretregs && !I16)
warning C6240: (<expression> && <non-zero constant>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
1895: { // Try not to always allocate the same register,
1896: // to schedule better
1897:
1898: r &= ~lastretregs;
1899: if (r & ~last2retregs)
1900: { r &= ~last2retregs;
1901: if (r & ~last3retregs)
1902: { r &= ~last3retregs;
1903: if (r & ~last4retregs)
1904: { r &= ~last4retregs;
1905: // if (r & ~last5retregs)
1906: // r &= ~last5retregs;
1907: }
1908: }
1909: }
1910: if (r & ~mfuncreg)
1911: r &= ~mfuncreg;
1912: }
1913: reg = findreg(r);
1914: retregs = mask[reg];
1915: }
1916: else if (size <= 2 * REGSIZE)
warning C4018: '<=' : signed/unsigned mismatch
1917: {
1918: /* Select pair with both regs free. Failing */
1919: /* that, select pair with one reg free. */
1920:
1921: if (r & mBP)
1922: { retregs &= ~mBP;
1923: goto L3;
1924: }
1925:
1926: if (r & mMSW)
1927: {
1928: if (r & mDX)
1929: msreg = DX; /* prefer to use DX over CX */
1930: else
1931: msreg = findregmsw(r);
1932: r &= mLSW; /* see if there's an LSW also */
1933: if (r)
1934: lsreg = findreg(r);
1935: else if (lsreg == -1) /* if don't have LSW yet */
1936: { retregs &= mLSW;
1937: goto L3;
1938: }
1939: }
1940: else
1941: {
1942: if (I64 && !(r & mLSW))
1943: { retregs = *pretregs & (mMSW | mLSW);
1944: assert(retregs);
1945: goto L1;
1946: }
1947: lsreg = findreglsw(r);
1948: if (msreg == -1)
1949: { retregs &= mMSW;
1950: assert(retregs);
1951: goto L3;
1952: }
1953: }
1954: reg = (msreg == ES) ? lsreg : msreg;
1955: retregs = mask[msreg] | mask[lsreg];
1956: }
1957: else if (I16 && (tym == TYdouble || tym == TYdouble_alias))
1958: {
1959: #ifdef DEBUG
1960: if (retregs != DOUBLEREGS)
1961: printf("retregs = x%x, *pretregs = x%x\n",retregs,*pretregs);
1962: #endif
1963: assert(retregs == DOUBLEREGS);
1964: reg = AX;
1965: }
1966: else
1967: {
1968: #ifdef DEBUG
1969: WRTYxx(tym);
1970: printf("\nallocreg: fil %s lin %d, regcon.mvar x%x msavereg x%x *pretregs x%x, reg %d, tym x%x\n",
1971: file,line,regcon.mvar,msavereg,*pretregs,*preg,tym);
1972: #endif
1973: assert(0);
1974: }
1975: if (retregs & regcon.mvar) // if conflict with reg vars
1976: {
1977: if (!(size > REGSIZE && *pretregs == (mAX | mDX)))
warning C4018: '>' : signed/unsigned mismatch
1978: {
1979: retregs = (*pretregs &= ~(retregs & regcon.mvar));
1980: goto L1; // try other registers
1981: }
1982: }
1983: *preg = reg;
1984: *pretregs = retregs;
1985:
1986: //printf("Allocating %s\n",regm_str(retregs));
1987: last5retregs = last4retregs;
1988: last4retregs = last3retregs;
1989: last3retregs = last2retregs;
1990: last2retregs = lastretregs;
1991: lastretregs = retregs;
1992: return getregs(retregs);
1993: }
1994:
1995: /*************************
1996: * Mark registers as used.
1997: */
1998:
1999: void useregs(regm_t regm)
2000: {
2001: //printf("useregs(x%x) %s\n", regm, regm_str(regm));
2002: mfuncreg &= ~regm;
2003: regcon.used |= regm; // registers used in this block
2004: regcon.params &= ~regm;
2005: if (regm & regcon.mpvar) // if modified a fastpar register variable
2006: regcon.params = 0; // toss them all out
2007: }
2008:
2009: /*************************
2010: * We are going to use the registers in mask r.
2011: * Generate any code necessary to save any regs.
2012: */
2013:
2014: code *getregs(regm_t r)
2015: { regm_t ms;
2016:
2017: //printf("getregs(x%x)\n",r);
2018: ms = r & regcon.cse.mops; // mask of common subs we must save
2019: useregs(r);
2020: regcon.cse.mval &= ~r;
2021: msavereg &= ~r; // regs that are destroyed
2022: regcon.immed.mval &= ~r;
2023: return ms ? cse_save(ms) : NULL;
2024: }
2025:
2026: /*****************************************
2027: * Copy registers in cse.mops into memory.
2028: */
2029:
2030: STATIC code * cse_save(regm_t ms)
2031: { unsigned reg,i,op;
2032: code *c = NULL;
2033: regm_t regm;
2034:
2035: assert((ms & regcon.cse.mops) == ms);
2036: regcon.cse.mops &= ~ms;
2037:
2038: /* Skip CSEs that are already saved */
2039: for (regm = 1; regm <= mES; regm <<= 1)
2040: {
2041: if (regm & ms)
2042: { elem *e;
2043:
2044: e = regcon.cse.value[findreg(regm)];
2045: for (i = 0; i < csmax; i++)
2046: {
2047: if (csextab[i].e == e)
2048: {
2049: tym_t tym;
2050: unsigned sz;
2051:
2052: tym = e->Ety;
2053: sz = tysize(tym);
2054: if (sz <= REGSIZE ||
warning C4018: '<=' : signed/unsigned mismatch
2055: sz <= 2 * REGSIZE &&
warning C4018: '<=' : signed/unsigned mismatch
2056: (regm & mMSW && csextab[i].regm & mMSW ||
2057: regm & mLSW && csextab[i].regm & mLSW) ||
2058: sz == 4 * REGSIZE && regm == csextab[i].regm
2059: )
2060: {
2061: ms &= ~regm;
2062: if (!ms)
2063: goto Lret;
2064: break;
2065: }
2066: }
2067: }
2068: }
2069: }
2070:
2071: for (i = cstop; ms; i++)
2072: {
2073: if (i >= csmax) /* array overflow */
2074: { unsigned cseinc;
2075:
2076: #ifdef DEBUG
2077: cseinc = 8; /* flush out reallocation bugs */
2078: #else
2079: cseinc = csmax + 32;
2080: #endif
2081: csextab = (struct CSE *) util_realloc(csextab,
2082: (csmax + cseinc), sizeof(csextab[0]));
2083: memset(&csextab[csmax],0,cseinc * sizeof(csextab[0]));
2084: csmax += cseinc;
2085: goto L1;
2086: }
2087: if (i >= cstop)
2088: {
2089: memset(&csextab[cstop],0,sizeof(csextab[0]));
2090: goto L1;
2091: }
2092: if (csextab[i].e == NULL || i >= cstop)
2093: {
2094: L1:
2095: reg = findreg(ms); /* the register to save */
2096: csextab[i].e = regcon.cse.value[reg];
2097: csextab[i].regm = mask[reg];
2098: csextab[i].flags &= CSEload;
2099: if (i >= cstop)
2100: cstop = i + 1;
2101:
2102: ms &= ~mask[reg]; /* turn off reg bit in ms */
2103:
2104: // If we can simply reload the CSE, we don't need to save it
2105: if (!cse_simple(csextab[i].e,i))
2106: {
2107: // MOV i[BP],reg
2108: op = 0x89; // normal mov
2109: if (reg == ES)
2110: { reg = 0; // the real reg number
2111: op = 0x8C; // segment reg mov
2112: }
2113: c = genc1(c,op,modregxrm(2, reg, BPRM),FLcs,(targ_uns) i);
2114: if (I64)
2115: code_orrex(c, REX_W);
2116: reflocal = TRUE;
2117: }
2118: }
2119: }
2120: Lret:
2121: return c;
2122: }
2123:
2124: /******************************************
2125: * Getregs without marking immediate register values as gone.
2126: */
2127:
2128: code *getregs_imm(regm_t r)
2129: { code *c;
2130: regm_t save;
2131:
2132: save = regcon.immed.mval;
2133: c = getregs(r);
2134: regcon.immed.mval = save;
2135: return c;
2136: }
2137:
2138: /******************************************
2139: * Flush all CSE's out of registers and into memory.
2140: * Input:
2141: * do87 !=0 means save 87 registers too
2142: */
2143:
2144: code *cse_flush(int do87)
2145: { code *c;
2146:
2147: //dbg_printf("cse_flush()\n");
2148: c = cse_save(regcon.cse.mops); // save any CSEs to memory
2149: if (do87)
2150: c = cat(c,save87()); // save any 8087 temporaries
2151: return c;
2152: }
2153:
2154: /*************************************************
2155: */
2156:
2157: STATIC int cse_simple(elem *e,int i)
2158: { regm_t regm;
2159: unsigned reg;
2160: code *c;
2161: int sz;
2162:
2163: sz = tysize[tybasic(e->Ety)];
2164: if (!I16 && // don't bother with 16 bit code
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
2165: e->Eoper == OPadd &&
2166: sz == REGSIZE &&
2167: e->E2->Eoper == OPconst &&
2168: e->E1->Eoper == OPvar &&
2169: isregvar(e->E1,®m,®) &&
2170: sz <= REGSIZE &&
2171: !(e->E1->EV.sp.Vsym->Sflags & SFLspill)
2172: )
2173: {
2174: c = &csextab[i].csimple;
2175: memset(c,0,sizeof(*c));
2176:
2177: // Make this an LEA instruction
2178: c->Iop = 0x8D; // LEA
2179: buildEA(c,reg,-1,1,e->E2->EV.Vuns);
2180: if (I64)
2181: { if (sz == 8)
2182: c->Irex |= REX_W;
2183: else if (sz == 1 && reg >= 4)
2184: c->Irex |= REX;
2185: }
2186:
2187: csextab[i].flags |= CSEsimple;
2188: return 1;
2189: }
2190: else if (e->Eoper == OPind &&
2191: sz <= REGSIZE &&
2192: e->E1->Eoper == OPvar &&
2193: isregvar(e->E1,®m,®) &&
2194: (I32 || I64 || regm & IDXREGS) &&
2195: !(e->E1->EV.sp.Vsym->Sflags & SFLspill)
2196: )
2197: {
2198: c = &csextab[i].csimple;
2199: memset(c,0,sizeof(*c));
2200:
2201: // Make this a MOV instruction
2202: c->Iop = (sz == 1) ? 0x8A : 0x8B; // MOV reg,EA
2203: buildEA(c,reg,-1,1,0);
2204: if (sz == 2 && I32)
2205: c->Iflags |= CFopsize;
2206: else if (I64)
2207: { if (sz == 8)
2208: c->Irex |= REX_W;
2209: else if (sz == 1 && reg >= 4)
2210: c->Irex |= REX;
2211: }
2212:
2213: csextab[i].flags |= CSEsimple;
2214: return 1;
2215: }
2216: return 0;
2217: }
2218:
2219: /*************************
2220: * Common subexpressions exist in registers. Note this in regcon.cse.mval.
2221: * Input:
2222: * e the subexpression
2223: * regm mask of registers holding it
2224: * opsflag if != 0 then regcon.cse.mops gets set too
2225: */
2226:
2227: void cssave(elem *e,regm_t regm,unsigned opsflag)
2228: { unsigned i;
2229:
2230: /*if (e->Ecount && e->Ecount == e->Ecomsub)*/
2231: if (e->Ecount && e->Ecomsub)
2232: {
2233: //printf("cssave(e = %p, regm = x%x, opsflag = %d)\n", e, regm, opsflag);
2234: if (!opsflag && pass != PASSfinal && (I32 || I64))
2235: return;
2236:
2237: //printf("cssave(e = %p, regm = x%x, opsflag = x%x)\n", e, regm, opsflag);
2238: regm &= mBP | ALLREGS | mES; /* just to be sure */
2239:
2240: #if 0
2241: /* Do not register CSEs if they are register variables and */
2242: /* are not operator nodes. This forces the register allocation */
2243: /* to go through allocreg(), which will prevent using register */
2244: /* variables for scratch. */
2245: if (opsflag || !(regm & regcon.mvar))
2246: #endif
2247: for (i = 0; regm; i++)
2248: { regm_t mi;
2249:
2250: mi = mask[i];
2251: if (regm & mi)
2252: {
2253: regm &= ~mi;
2254:
2255: // If we don't need this CSE, and the register already
2256: // holds a CSE that we do need, don't mark the new one
2257: if (regcon.cse.mval & mi && regcon.cse.value[i] != e &&
2258: !opsflag && regcon.cse.mops & mi)
2259: continue;
2260:
2261: regcon.cse.mval |= mi;
2262: if (opsflag)
2263: regcon.cse.mops |= mi;
2264: //printf("cssave set: regcon.cse.value[%s] = %p\n",regstring[i],e);
2265: regcon.cse.value[i] = e;
2266: }
2267: }
2268: }
2269: }
2270:
2271: /*************************************
2272: * Determine if a computation should be done into a register.
2273: */
2274:
2275: bool evalinregister(elem *e)
2276: { regm_t emask;
2277: unsigned i;
2278: unsigned sz;
2279:
2280: if (e->Ecount == 0) /* elem is not a CSE, therefore */
2281: /* we don't need to evaluate it */
2282: /* in a register */
2283: return FALSE;
2284: if (EOP(e)) /* operators are always in register */
2285: return TRUE;
2286: sz = tysize(e->Ety);
2287: if (e->Ecount == e->Ecomsub) /* elem is a CSE that needs */
2288: /* to be generated */
2289: {
2290: if ((I32 || I64) && pass == PASSfinal && sz <= REGSIZE)
warning C4018: '<=' : signed/unsigned mismatch
2291: {
2292: // Do it only if at least 2 registers are available
2293: regm_t m;
2294:
2295: m = allregs & ~regcon.mvar;
2296: if (sz == 1)
2297: m &= BYTEREGS;
2298: if (m & (m - 1)) // if more than one register
2299: { // Need to be at least 3 registers available, as
2300: // addressing modes can use up 2.
2301: while (!(m & 1))
2302: m >>= 1;
2303: m >>= 1;
2304: if (m & (m - 1))
2305: return TRUE;
2306: }
2307: }
2308: return FALSE;
2309: }
2310:
2311: /* Elem is now a CSE that might have been generated. If so, and */
2312: /* it's in a register already, the computation should be done */
2313: /* using that register. */
2314: emask = 0;
2315: for (i = 0; i < arraysize(regcon.cse.value); i++)
2316: if (regcon.cse.value[i] == e)
2317: emask |= mask[i];
2318: emask &= regcon.cse.mval; // mask of available CSEs
2319: if (sz <= REGSIZE)
warning C4018: '<=' : signed/unsigned mismatch
2320: return emask != 0; /* the CSE is in a register */
2321: else if (sz <= 2 * REGSIZE)
warning C4018: '<=' : signed/unsigned mismatch
2322: return (emask & mMSW) && (emask & mLSW);
2323: return TRUE; /* cop-out for now */
2324: }
2325:
2326: /*******************************************************
2327: * Return mask of scratch registers.
2328: */
2329:
2330: regm_t getscratch()
2331: { regm_t scratch;
2332:
2333: scratch = 0;
2334: if (pass == PASSfinal)
2335: {
2336: scratch = allregs & ~(regcon.mvar | regcon.mpvar | regcon.cse.mval |
2337: regcon.immed.mval | regcon.params | mfuncreg);
2338: }
2339: return scratch;
2340: }
2341:
2342: /******************************
2343: * Evaluate an elem that is a common subexp that has been encountered
2344: * before.
2345: * Look first to see if it is already in a register.
2346: */
2347:
2348: STATIC code * comsub(elem *e,regm_t *pretregs)
2349: { tym_t tym;
2350: regm_t regm,emask,csemask;
2351: unsigned reg,i,byte,sz;
2352: code *c;
2353:
2354: //printf("comsub(e = %p, *pretregs = %s)\n",e,regm_str(*pretregs));
2355: elem_debug(e);
2356: #ifdef DEBUG
2357: if (e->Ecomsub > e->Ecount)
2358: elem_print(e);
2359: #endif
2360: assert(e->Ecomsub <= e->Ecount);
2361:
2362: c = CNIL;
2363: if (*pretregs == 0) goto done; /* no possible side effects anyway */
2364:
2365: if (tyfloating(e->Ety) && config.inline8087)
2366: return comsub87(e,pretregs);
2367:
2368: /* First construct a mask, emask, of all the registers that */
2369: /* have the right contents. */
2370:
2371: emask = 0;
2372: for (i = 0; i < arraysize(regcon.cse.value); i++)
2373: {
2374: //dbg_printf("regcon.cse.value[%d] = %p\n",i,regcon.cse.value[i]);
2375: if (regcon.cse.value[i] == e) /* if contents are right */
2376: emask |= mask[i]; /* turn on bit for reg */
2377: }
2378: emask &= regcon.cse.mval; /* make sure all bits are valid */
2379:
2380: /* create mask of what's in csextab[] */
2381: csemask = 0;
2382: for (i = 0; i < cstop; i++)
2383: { if (csextab[i].e)
2384: elem_debug(csextab[i].e);
2385: if (csextab[i].e == e)
warning C4390: ';' : empty controlled statement found; is this the intent?
2386: csemask |= csextab[i].regm;
2387: }
2388: csemask &= ~emask; /* stuff already in registers */
2389:
2390: #ifdef DEBUG
2391: if (debugw)
2392: {
2393: printf("comsub(e=%p): *pretregs=%x, emask=%x, csemask=%x, regcon.cse.mval=%x, regcon.mvar=%x\n",
2394: e,*pretregs,emask,csemask,regcon.cse.mval,regcon.mvar);
2395: if (regcon.cse.mval & 1) elem_print(regcon.cse.value[i]);
2396: }
2397: #endif
2398:
2399: tym = tybasic(e->Ety);
2400: sz = tysize[tym];
2401: byte = sz == 1;
2402:
2403: if (sz <= REGSIZE) // if data will fit in one register
warning C4018: '<=' : signed/unsigned mismatch
2404: {
2405: /* First see if it is already in a correct register */
2406:
2407: regm = emask & *pretregs;
2408: if (regm == 0)
2409: regm = emask; /* try any other register */
2410: if (regm) /* if it's in a register */
2411: {
2412: if (EOP(e) || !(regm & regcon.mvar) || (*pretregs & regcon.mvar) == *pretregs)
2413: {
2414: regm = mask[findreg(regm)];
2415: goto fix;
2416: }
2417: }
2418:
2419: if (!EOP(e)) /* if not op or func */
2420: goto reload; /* reload data */
2421: for (i = cstop; i--;) /* look through saved comsubs */
2422: if (csextab[i].e == e) /* found it */
2423: { regm_t retregs;
2424:
2425: if (csextab[i].flags & CSEsimple)
2426: { code *cr;
2427:
2428: retregs = *pretregs;
2429: if (byte && !(retregs & BYTEREGS))
2430: retregs = BYTEREGS;
2431: else if (!(retregs & allregs))
2432: retregs = allregs;
2433: c = allocreg(&retregs,®,tym);
2434: cr = &csextab[i].csimple;
2435: cr->setReg(reg);
2436: c = gen(c,cr);
2437: goto L10;
2438: }
2439: else
2440: {
2441: reflocal = TRUE;
2442: csextab[i].flags |= CSEload;
2443: if (*pretregs == mPSW) /* if result in CCs only */
2444: { // CMP cs[BP],0
2445: c = genc(NULL,0x81 ^ byte,modregrm(2,7,BPRM),
2446: FLcs,i, FLconst,(targ_uns) 0);
2447: if (I32 && sz == 2)
2448: c->Iflags |= CFopsize;
2449: }
2450: else
2451: {
2452: retregs = *pretregs;
2453: if (byte && !(retregs & BYTEREGS))
2454: retregs = BYTEREGS;
2455: c = allocreg(&retregs,®,tym);
2456: // MOV reg,cs[BP]
2457: c = genc1(c,0x8B,modregxrm(2,reg,BPRM),FLcs,(targ_uns) i);
2458: if (I64)
2459: code_orrex(c, REX_W);
2460: L10:
2461: regcon.cse.mval |= mask[reg]; // cs is in a reg
2462: regcon.cse.value[reg] = e;
2463: c = cat(c,fixresult(e,retregs,pretregs));
2464: }
2465: }
2466: freenode(e);
2467: return c;
2468: }
2469: #ifdef DEBUG
2470: printf("couldn't find cse e = %p, pass = %d\n",e,pass);
2471: elem_print(e);
2472: #endif
2473: assert(0); /* should have found it */
2474: }
2475: else /* reg pair is req'd */
2476: if (sz <= 2 * REGSIZE)
warning C4018: '<=' : signed/unsigned mismatch
2477: { unsigned msreg,lsreg;
2478:
2479: /* see if we have both */
2480: if (!((emask | csemask) & mMSW && (emask | csemask) & (mLSW | mBP)))
2481: { /* we don't have both */
2482: #if DEBUG
2483: if (EOP(e))
2484: {
2485: printf("e = %p, op = x%x, emask = x%x, csemask = x%x\n",
2486: e,e->Eoper,emask,csemask);
2487: //printf("mMSW = x%x, mLSW = x%x\n", mMSW, mLSW);
2488: elem_print(e);
2489: }
2490: #endif
2491: assert(!EOP(e)); /* must have both for operators */
2492: goto reload;
2493: }
2494:
2495: /* Look for right vals in any regs */
2496:
2497: regm = *pretregs & mMSW;
2498: if (emask & regm)
2499: msreg = findreg(emask & regm);
2500: else if (emask & mMSW)
2501: msreg = findregmsw(emask);
2502: else /* reload from cse array */
2503: {
2504: if (!regm)
2505: regm = mMSW & ALLREGS;
2506: c = allocreg(®m,&msreg,TYint);
2507: c = cat(c,loadcse(e,msreg,mMSW));
2508: }
2509:
2510: regm = *pretregs & (mLSW | mBP);
2511: if (emask & regm)
2512: lsreg = findreg(emask & regm);
2513: else if (emask & (mLSW | mBP))
2514: lsreg = findreglsw(emask);
2515: else
2516: {
2517: if (!regm)
2518: regm = mLSW;
2519: c = cat(c,allocreg(®m,&lsreg,TYint));
2520: c = cat(c,loadcse(e,lsreg,mLSW | mBP));
2521: }
2522:
2523: regm = mask[msreg] | mask[lsreg]; /* mask of result */
2524: goto fix;
2525: }
2526: else if (tym == TYdouble || tym == TYdouble_alias) // double
2527: {
2528: assert(I16);
2529: if (((csemask | emask) & DOUBLEREGS_16) == DOUBLEREGS_16)
2530: {
2531: for (reg = AX; reg != -1; reg = dblreg[reg])
2532: { assert((int) reg >= 0 && reg <= 7);
2533: if (mask[reg] & csemask)
2534: c = cat(c,loadcse(e,reg,mask[reg]));
2535: }
2536: regm = DOUBLEREGS_16;
2537: goto fix;
2538: }
2539: if (!EOP(e)) goto reload;
2540: #if DEBUG
2541: printf("e = %p, csemask = x%x, emask = x%x\n",e,csemask,emask);
2542: #endif
2543: assert(0);
2544: }
2545: else
2546: {
2547: #if DEBUG
2548: printf("e = %p, tym = x%x\n",e,tym);
2549: #endif
2550: assert(0);
2551: }
2552:
2553: reload: /* reload result from memory */
2554: switch (e->Eoper)
2555: {
2556: case OPrelconst:
2557: c = cdrelconst(e,pretregs);
2558: break;
2559: #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
2560: case OPgot:
2561: c = cdgot(e,pretregs);
2562: break;
2563: #endif
2564: default:
2565: c = loaddata(e,pretregs);
2566: break;
2567: }
2568: cssave(e,*pretregs,FALSE);
2569: freenode(e);
2570: return c;
2571:
2572: fix: /* we got result in regm, fix */
2573: c = cat(c,fixresult(e,regm,pretregs));
2574: done:
2575: freenode(e);
2576: return c;
2577: }
2578:
2579:
2580: /*****************************
2581: * Load reg from cse stack.
2582: * Returns:
2583: * pointer to the MOV instruction
2584: */
2585:
2586: STATIC code * loadcse(elem *e,unsigned reg,regm_t regm)
2587: { unsigned i,op;
2588: code *c;
2589:
2590: for (i = cstop; i--;)
2591: {
2592: //printf("csextab[%d] = %p, regm = x%x\n", i, csextab[i].e, csextab[i].regm);
2593: if (csextab[i].e == e && csextab[i].regm & regm)
2594: {
2595: reflocal = TRUE;
2596: csextab[i].flags |= CSEload; /* it was loaded */
2597: c = getregs(mask[reg]);
2598: regcon.cse.value[reg] = e;
2599: regcon.cse.mval |= mask[reg];
2600: op = 0x8B;
2601: if (reg == ES)
2602: { op = 0x8E;
2603: reg = 0;
2604: }
2605: c = genc1(c,op,modregxrm(2,reg,BPRM),FLcs,(targ_uns) i);
2606: if (I64)
2607: code_orrex(c, REX_W);
2608: return c;
2609: }
2610: }
2611: #if DEBUG
2612: printf("loadcse(e = %p, reg = %d, regm = x%x)\n",e,reg,regm);
2613: elem_print(e);
2614: #endif
2615: assert(0);
2616: /* NOTREACHED */
2617: return 0;
2618: }
2619:
2620: /***************************
2621: * Generate code sequence for an elem.
2622: * Input:
2623: * pretregs mask of possible registers to return result in
2624: * Note: longs are in AX,BX or CX,DX or SI,DI
2625: * doubles are AX,BX,CX,DX only
2626: * constflag TRUE if user of result will not modify the
2627: * registers returned in *pretregs.
2628: * Output:
2629: * *pretregs mask of registers result is returned in
2630: * Returns:
2631: * pointer to code sequence generated
2632: */
2633:
2634: #include "cdxxx.c" /* jump table */
2635:
2636: code *codelem(elem *e,regm_t *pretregs,bool constflag)
2637: { code *c;
2638: Symbol *s;
2639: unsigned op;
2640:
2641: #ifdef DEBUG
2642: if (debugw)
2643: { printf("+codelem(e=%p,*pretregs=%s) ",e,regm_str(*pretregs));
2644: WROP(e->Eoper);
2645: printf("msavereg=x%x regcon.cse.mval=x%x regcon.cse.mops=x%x\n",
2646: msavereg,regcon.cse.mval,regcon.cse.mops);
2647: printf("Ecount = %d, Ecomsub = %d\n", e->Ecount, e->Ecomsub);
2648: }
2649: #endif
2650: assert(e);
2651: elem_debug(e);
2652: if ((regcon.cse.mops & regcon.cse.mval) != regcon.cse.mops)
2653: {
2654: #ifdef DEBUG
2655: printf("+codelem(e=%p,*pretregs=x%x) ",e,*pretregs);
2656: elem_print(e);
2657: printf("msavereg=x%x regcon.cse.mval=x%x regcon.cse.mops=x%x\n",
2658: msavereg,regcon.cse.mval,regcon.cse.mops);
2659: printf("Ecount = %d, Ecomsub = %d\n", e->Ecount, e->Ecomsub);
2660: #endif
2661: assert(0);
2662: }
2663:
2664: if (!constflag && *pretregs & (mES | ALLREGS | mBP) & ~regcon.mvar)
2665: *pretregs &= ~regcon.mvar; /* can't use register vars */
2666: op = e->Eoper;
2667: if (e->Ecount && e->Ecount != e->Ecomsub) /* if common subexp */
2668: { c = comsub(e,pretregs);
2669: goto L1;
2670: }
2671:
2672: switch (op)
2673: {
2674: default:
2675: if (e->Ecount) /* if common subexp */
2676: {
2677: /* if no return value */
2678: if ((*pretregs & (mSTACK | mES | ALLREGS | mBP)) == 0)
2679: { if (tysize(e->Ety) == 1)
2680: *pretregs |= BYTEREGS;
2681: else if (tybasic(e->Ety) == TYdouble || tybasic(e->Ety) == TYdouble_alias)
2682: *pretregs |= DOUBLEREGS;
2683: else
2684: *pretregs |= ALLREGS; /* make one */
2685: }
2686:
2687: /* BUG: For CSEs, make sure we have both an MSW */
2688: /* and an LSW specified in *pretregs */
2689: }
2690: assert(op <= OPMAX);
2691: c = (*cdxxx[op])(e,pretregs);
2692: break;
2693: case OPrelconst:
2694: c = cdrelconst(e,pretregs);
2695: break;
2696: case OPvar:
2697: if (constflag && (s = e->EV.sp.Vsym)->Sfl == FLreg &&
2698: (s->Sregm & *pretregs) == s->Sregm)
2699: {
2700: if (tysize(e->Ety) <= REGSIZE && tysize(s->Stype->Tty) == 2 * REGSIZE)
2701: *pretregs &= mPSW | (s->Sregm & mLSW);
2702: else
2703: *pretregs &= mPSW | s->Sregm;
2704: }
2705: case OPconst:
2706: if (*pretregs == 0 && (e->Ecount >= 3 || e->Ety & mTYvolatile))
2707: {
2708: switch (tybasic(e->Ety))
2709: {
2710: case TYbool:
2711: case TYchar:
2712: case TYschar:
2713: case TYuchar:
2714: *pretregs |= BYTEREGS;
2715: break;
2716: #if JHANDLE
2717: case TYjhandle:
2718: #endif
2719: case TYnptr:
2720: case TYsptr:
2721: case TYcptr:
2722: *pretregs |= IDXREGS;
2723: break;
2724: case TYshort:
2725: case TYushort:
2726: case TYint:
2727: case TYuint:
2728: case TYlong:
2729: case TYulong:
2730: case TYllong:
2731: case TYullong:
2732: case TYcent:
2733: case TYucent:
2734: #if !TARGET_FLAT
2735: case TYfptr:
2736: case TYhptr:
2737: #endif
2738: case TYvptr:
2739: *pretregs |= ALLREGS;
2740: break;
2741: }
2742: }
2743: c = loaddata(e,pretregs);
2744: break;
2745: }
2746: cssave(e,*pretregs,!OTleaf(op));
2747: freenode(e);
2748: L1:
2749: #ifdef DEBUG
2750: if (debugw)
2751: { printf("-codelem(e=%p,*pretregs=x%x) ",e,*pretregs);
2752: WROP(op);
2753: printf("msavereg=x%x regcon.cse.mval=x%x regcon.cse.mops=x%x\n",
2754: msavereg,regcon.cse.mval,regcon.cse.mops);
2755: }
2756: #endif
2757: if (configv.addlinenumbers && e->Esrcpos.Slinnum)
2758: cgen_prelinnum(&c,e->Esrcpos);
2759: return c;
2760: }
2761:
2762: /*********************************************
2763: * Turn register mask into a string suitable for printing.
2764: */
2765:
2766: #ifdef DEBUG
2767:
2768: const char *regm_str(regm_t rm)
2769: {
2770: #define NUM 4
2771: #define SMAX 64
2772: static char str[NUM][SMAX + 1];
2773: static int i;
2774: char *p;
2775: int j;
2776:
2777: if (rm == 0)
2778: return "0";
2779: if (rm == ALLREGS)
2780: return "ALLREGS";
2781: if (rm == BYTEREGS)
2782: return "BYTEREGS";
2783: if (rm == allregs)
2784: return "allregs";
2785: p = str[i];
2786: if (++i == NUM)
2787: i = 0;
2788: *p = 0;
2789: for (j = 0; j < 32; j++)
2790: {
2791: if (mask[j] & rm)
2792: {
2793: strcat(p,regstring[j]);
2794: rm &= ~mask[j];
2795: if (rm)
2796: strcat(p,"|");
2797: }
2798: }
2799: if (rm)
2800: { char *s = p + strlen(p);
2801: sprintf(s,"x%02x",rm);
2802: }
2803: assert(strlen(p) <= SMAX);
2804: return strdup(p);
2805: }
2806:
2807: #endif
2808:
2809: #endif // !SPP
2810: