|
|
1.1 root 1: /*
2: * n0/i386/bind.c
3: * Machine-specific parts of the C compiler parser.
4: * i386.
5: */
6:
7: #ifdef vax
8: #include "INC$LIB:cc0.h"
9: #else
10: #include "cc0.h"
11: #endif
12:
13: /* Local stack: local offset and register mask. */
14: typedef struct locals {
15: struct locals *l_lstp;
16: ival_t l_lofs;
17: int l_mask;
18: } LOCALS;
19:
20: LOCALS *clstp; /* Local stack */
21: ival_t clofs; /* Current local offset */
22: int cmask; /* Current mask */
23: ival_t llofs; /* Last local offset reported */
24: int lmask; /* Last register mask reported */
25: int alignment; /* Alignment from #pragma */
26:
27: /*
28: * This table is indexed by C type to obtain the size
29: * in bytes of a machine object.
30: */
31: int mysizes[] = {
32: 0, /* T_NONE */
33: 1, 1, /* T_CHAR T_UCHAR */
34: 2, 2, /* T_SHORT T_USHORT */
35: 4, 4, /* T_INT T_UINT */
36: 4, /* T_PTR */
37: 4, 4, /* T_LONG T_ULONG */
38: 4, 8, /* T_FLOAT T_DOUBLE */
39: 0, /* T_VOID */
40: 0, 0, /* T_STRUCT T_FSTRUCT */
41: 0, 0, /* T_UNION T_FUNION */
42: 0, 0 /* T_ENUM T_FENUM */
43: };
44:
45: /*
46: * This table is indexed by C type to obtain the machine type,
47: * as defined in 'mch.h'.
48: */
49: char mytypes[] = {
50: 0, /* T_NONE */
51: S8, U8, /* T_CHAR T_UCHAR */
52: S16, U16, /* T_SHORT T_USHORT */
53: S32, U32, /* T_INT T_UINT */
54: PTR, /* T_PTR */
55: S32, U32, /* T_LONG T_ULONG */
56: F32, F64, /* T_FLOAT T_DOUBLE */
57: S32, /* T_VOID */
58: BLK, 0, /* T_STRUCT T_FSTRUCT */
59: BLK, 0, /* T_UNION T_FUNION */
60: 0, 0 /* T_ENUM T_FENUM */
61: };
62:
63: /*
64: * main() calls this routine to perform machine-dependent parser setup.
65: */
66: vinit()
67: {
68: #if MONOLITHIC
69: alignment = 0;
70: #endif
71: }
72:
73: /*
74: * Empty the local binding stack and mark the unavailable registers.
75: */
76: initlocals()
77: {
78: clstp = NULL;
79: llofs = clofs = 0;
80: lmask = cmask = BESP|BEBP;
81: bput(AUTOS);
82: iput(clofs);
83: iput((ival_t)cmask);
84: }
85:
86: /*
87: * Save the current state of the local bindings.
88: */
89: savelocals()
90: {
91: register LOCALS *lstp;
92:
93: lstp = (LOCALS *) new(sizeof(LOCALS));
94: lstp->l_lstp = clstp;
95: lstp->l_lofs = clofs;
96: lstp->l_mask = cmask;
97: clstp = lstp;
98: }
99:
100: /*
101: * Restore locals.
102: * Tell the code generator if it changes.
103: */
104: restlocals()
105: {
106: register LOCALS *lstp;
107:
108: if ((lstp=clstp) == NULL)
109: cbotch("restlocals");
110: clstp = lstp->l_lstp;
111: clofs = lstp->l_lofs;
112: cmask = lstp->l_mask;
113: putautos();
114: free((char *) lstp);
115: }
116:
117: /*
118: * Inform the code generator (and perhaps the optimizer)
119: * about the current automatic variable allocation.
120: */
121: putautos()
122: {
123: if (clofs != llofs || cmask != lmask) {
124: llofs = clofs;
125: lmask = cmask;
126: bput(AUTOS);
127: iput(-clofs);
128: iput((ival_t)cmask);
129: }
130: }
131:
132: /*
133: * Bind locals to the correct place on the stack frame.
134: * Locals grow down from EBP, e.g. EBP-4, EBP-8, etc.
135: */
136: bindlocal(sp) register SYM *sp;
137: {
138: register int c, regno;
139:
140: if ((c = sp->s_class) == C_REG) {
141: if ((regno = grabreg(sp)) >= 0) {
142: sp->s_value = regno;
143: return;
144: }
145: /* Demote register local to auto. */
146: setclass(sp, C_AUTO);
147: }
148: if (c==C_AUTO || c==C_REG) {
149: clofs -= ssize(sp);
150: /* Keep stack dword-aligned. */
151: if ((clofs & 3) != 0)
152: clofs &= ~3;
153: sp->s_value = clofs;
154: if (clofs >= 0)
155: cerror("auto \"%s\" is not addressable", sp->s_id);
156: }
157: }
158:
159: /*
160: * Attempt to get a register for symbol 'sp'.
161: * Only integer dword objects go in registers currently.
162: * Chars, shorts and floats could go in registers if loadreg() were changed.
163: * Return register id if successful, -1 otherwise.
164: */
165: grabreg(sp) register SYM *sp;
166: {
167: register DIM *dp;
168: register int type;
169:
170: if ((dp = sp->s_dp) != NULL)
171: return (dp->d_type == D_PTR) ? allocreg() : -1;
172: type = sp->s_type;
173: if (type >= T_INT && type <= T_ULONG)
174: return allocreg();
175: return -1;
176: }
177: /*
178: * Allocate a register.
179: * Currently allocates EBX, ESI and EDI.
180: * Return register id if successful, -1 otherwise.
181: */
182: int
183: allocreg()
184: {
185: if ((cmask&BEBX) == 0) {
186: cmask |= BEBX;
187: return EBX;
188: } else if ((cmask&BESI) == 0) {
189: cmask |= BESI;
190: return ESI;
191: } else if ((cmask&BEDI) == 0) {
192: cmask |= BEDI;
193: return EDI;
194: } else
195: return -1;
196: }
197:
198: /*
199: * Bind arguments.
200: * Stack frame during function execution:
201: * ...
202: * ebp+8 arg1
203: * ebp+4 return address
204: * ebp saved ebp
205: * ebp-4 auto1
206: * ...
207: ebp-n autolast
208: * ebp-n-4 saved esi [if required]
209: * ebp-n-8 saved edi [if required]
210: * ebp-n-12 saved ebx [if required]
211: */
212: bindargs()
213: {
214: register SYM *sp;
215: register int i;
216: register ival_t offset;
217:
218: offset = 8; /* arg1 offset */
219: for (i = 0; i < nargs; ++i) {
220: sp = args[i];
221: if (sp->s_class != C_PREG)
222: sp->s_class = C_PAUTO;
223: sp->s_value = offset;
224: offset += ssize(sp);
225: /* Keep parameters dword-aligned. */
226: if ((offset & 3) != 0)
227: offset = (offset + 3) & ~3;
228: }
229: }
230:
231: /*
232: * Copy register arguments from the stack into the register.
233: * Change class of the argument to plain register.
234: * Note that bindargs() has put the stack displacement
235: * into the 's_value' field of the argument symbol.
236: */
237: loadargs()
238: {
239: register SYM *sp;
240: register int i, r;
241: register ival_t v;
242:
243: for (i = 0; i < nargs; ++i) {
244: sp = args[i];
245: if (sp->s_class == C_PREG) {
246: if ((r=grabreg(sp)) >= 0) {
247: v = sp->s_value; /* stack offset */
248: sp->s_class = C_REG;
249: sp->s_value = r; /* register number */
250: loadreg(sp, v);
251: continue;
252: }
253: /* Demote parametric register to parametric auto. */
254: setclass(sp, C_PAUTO);
255: }
256: }
257: }
258:
259: /*
260: * Change the storage class of sp.
261: * Issue a 'strict' warning if desired.
262: */
263: setclass(sp, c) register SYM *sp; int c;
264: {
265: sp->s_class = c;
266: if (isvariant(VSNREG))
267: cstrict("identifier \"%s\" not bound to register", sp->s_id);
268: }
269:
270: /*
271: * Load symbol 'sp' from offset 'offset' in the frame.
272: * Since register variables are always dwords,
273: * the type can always be setup to T_INT.
274: */
275: loadreg(sp, offset) SYM *sp; ival_t offset;
276: {
277: register TREE *lp, *rp, *tp;
278:
279: newtree(sizeof(TREE));
280: lp = talloc();
281: lp->t_op = REG;
282: lp->t_type = T_INT;
283: lp->t_reg = sp->s_value;
284: rp = talloc();
285: rp->t_op = PID;
286: rp->t_type = T_INT;
287: rp->t_offs = offset;
288: tp = build(ASSIGN, lp, rp);
289: putautos();
290: tput(EEXPR, 0, tp);
291: }
292:
293: /*
294: * Process a #pragma.
295: * Currently recognizes only "#pragma align [n]".
296: * Return 1 if recognized, 0 if not.
297: */
298: pragma(p) char *p;
299: {
300: static char align[] = "align";
301:
302: while (*p == ' ' || *p == '\t')
303: ++p;
304: if (strncmp(align, p, sizeof(align)-1) == 0) {
305: alignment = atoi(p + sizeof(align)-1);
306: if (alignment < 0) {
307: cerror("#pragma align: bad alignment %d", alignment);
308: alignment = 0;
309: }
310: return 1;
311: }
312: return 0;
313: }
314:
315: /*
316: * Look at type 't', DIM list 'dp' and field width 'w' (0 for non fields)
317: * and return the bit offset of the base of the structure member.
318: * The 'offset' argument is the current bit offset in the structure or union.
319: * Check for fields that are too wide, bad field base types, and arrange
320: * that the byte, word or dword that spans the field can be grabbed in one grab.
321: * See comments in bindlocal() above concerning reals and bitfield alignment.
322: */
323: long
324: fieldalign(t, dp, ip, w, offset)
325: register DIM *dp;
326: INFO *ip;
327: register int w;
328: long offset;
329: {
330: register long bitwidth, amask, a;
331:
332: /*
333: * Find bit width of type t;
334: * e.g. 8 for char, 16 for short, 32 for int or ptr.
335: */
336: if (dp != NULL) {
337: switch(dp->d_type) {
338: case D_FUNC: t = T_PTR; break;
339: case D_PTR: t = T_PTR; break;
340: case D_ARRAY: break;
341: case D_MOSAR: break;
342: default: cbotch("fieldalign %d", dp->d_type);
343: }
344: } else if (t == T_FENUM)
345: t = T_INT;
346: else if (t == T_ENUM)
347: t = ip->i_type;
348: if (alignment == 0) {
349: if (t == T_STRUCT || t == T_UNION)
350: bitwidth = 8 * saligntype(ip);
351: else
352: bitwidth = 8 * mysizes[t];
353: if (bitwidth == 0)
354: bitwidth = 32;
355: amask = bitwidth - 1;
356: } else {
357: if (t == T_STRUCT || t == T_UNION)
358: a = saligntype(ip);
359: else
360: a = (mysizes[t] == 0) ? 4 : mysizes[t];
361: amask = 8 * ((a < alignment) ? a : alignment) - 1;
362: bitwidth = 8 * a;
363: }
364: if (w != 0) {
365: /* Nonzero width bitfield. */
366: if (dp != NULL)
367: cerror("non scalar field");
368: if (bitwidth > 32)
369: cerror("bad base type for field");
370: #if 0
371: if (w > bitwidth)
372: cerror("field too wide");
373: #endif
374: /* Bump to next alignment boundary if necessary. */
375: if ((offset & amask) + w > bitwidth)
376: offset = (offset + amask) & ~amask;
377: } else {
378: /* Zero width bitfield or non field. */
379: offset = (offset + amask) & ~amask;
380: }
381: return offset;
382: }
383:
384: /*
385: * Convert a tree into its low level form.
386: * Fill in the machine type byte looking at the C type
387: * and the segment information.
388: */
389: TREE *
390: transform(tp, why, above) register TREE *tp; int why, above;
391: {
392: register TREE *lp;
393: register int t;
394: register int wd;
395:
396: /*
397: * The way that this code looks at the DIM lists to decide
398: * what type of conversion is inserted makes me sick.
399: * The correct type of conversion node (MUL, DIV, etc.)
400: * should really be inserted when the tree is constructed,
401: * guided by a table.
402: */
403: if (tp->t_op == CONVERT) {
404: lp = tp->t_lp;
405: if (tp->t_dp!=NULL && lp->t_dp==NULL && why!=REXPR) {
406: tp->t_op = MUL;
407: tp->t_dp = NULL;
408: if (lp->t_type != T_INT)
409: tp->t_lp = bconvert(lp, T_INT, NULL,NULL,NULL);
410: tp->t_type = T_INT;
411: } else if (tp->t_dp==NULL && lp->t_dp!=NULL && tp->t_rp!=NULL) {
412: tp->t_op = DIV;
413: lp->t_dp = NULL;
414: lp->t_type = T_INT;
415: }
416: }
417:
418: /* Fixup any remaining ZCONs. */
419: if (tp->t_op == ZCON) {
420: tp->t_op = ICON;
421: tp->t_type = T_INT;
422: tp->t_ival = tp->t_zval;
423: }
424:
425: /* Set the type field. */
426: if (tp->t_dp != NULL)
427: tp->t_type = mytypes[T_PTR];
428: else if ((t=tp->t_type)==T_FSTRUCT || t==T_FUNION || t==T_FENUM) {
429: unksize(t, tp->t_ip);
430: tp->t_type = S32; /* default to S32 */
431: } else {
432: if (t == T_ENUM)
433: t = tp->t_ip->i_type; /* enum base type */
434: tp->t_type = mytypes[t];
435: }
436:
437: if (tp->t_op >= MIOBASE) {
438: wd = why;
439: if (why == REXPR)
440: wd = EEXPR;
441: tp->t_lp = transform(tp->t_lp, wd, tp->t_op);
442: if (tp->t_op!=FIELD && tp->t_rp!=NULL)
443: tp->t_rp = transform(tp->t_rp, wd, -1);
444: if (tp->t_op==CONVERT && tp->t_rp==NULL) {
445: lp = tp->t_lp;
446: if (tp->t_type == lp->t_type)
447: tp = lp;
448: }
449: }
450: return tp;
451: }
452:
453: /*
454: * Check if the operator 'op' applied to C types 'lt' and 'rt'
455: * (which are outputs from tltype(), which means that all pointers
456: * have been converted to type T_PTR) involves no conversions.
457: * This means the code generator must deal with the type mismatch.
458: */
459: noconvert(op, lt, rt) register int op, lt, rt;
460: {
461: if (op==ASSIGN || op==CAST || (op>=EQ && op<=ULT)) {
462: if ((lt>=T_CHAR && lt<=T_UCHAR)
463: && (rt>=T_CHAR && rt<=T_UCHAR))
464: return 1; /* 8-bit types */
465: if ((lt>=T_SHORT && lt<=T_USHORT)
466: && (rt>=T_SHORT && rt<=T_USHORT))
467: return 1; /* 16-bit types */
468: if ((lt>=T_INT && lt<=T_ULONG)
469: && (rt>=T_INT && rt<=T_ULONG))
470: return 1; /* 32-bit types */
471: if (op==CAST && lt==T_FLOAT && rt==T_DOUBLE)
472: return 1; /* (float)double */
473: }
474: return 0;
475: }
476:
477: /*
478: * Align the location counter well enough for the object 'sp'.
479: */
480: align(sp) SYM *sp;
481: {
482: bput(ALIGN);
483: bput(aligntype(sp));
484: }
485:
486: /*
487: * Return the appropriate alignment type for 'sp'.
488: * The alignment type is 1 for byte, 2 for word, 4 for dword.
489: */
490: aligntype(sp) SYM *sp;
491: {
492: register int type, atype, dtype;
493: register DIM *dp;
494:
495: if (alignment != 0)
496: return alignment; /* use #pragma-defined alignment */
497: type = sp->s_type;
498: atype = mysizes[type];
499: if ((dp = sp->s_dp) != NULL) {
500: while (dp != NULL
501: && ((dtype = dp->d_type) == D_ARRAY || dtype == D_MOSAR))
502: dp = dp->d_dp;
503: if (dtype == D_PTR || dtype == D_FUNC)
504: return 4; /* pointer to, function returning */
505: }
506: if (atype == 1 || atype == 2 || (atype == 4 && type != T_PTR))
507: return atype; /* chars, shorts, ints, longs, floats */
508: else if (type == T_DOUBLE)
509: return 4; /* dword alignment, not qword */
510: else if (type == T_STRUCT || type == T_UNION)
511: return saligntype(sp->s_ip);
512: else if (type == T_ENUM)
513: return mytypes[sp->s_ip->i_type]; /* enum base type */
514: else if (type == T_FSTRUCT || type == T_FUNION || type == T_FENUM) {
515: cerror("alignment of %s \"%s\" is not known",
516: (type == T_FSTRUCT) ? "struct"
517: : (type == T_FUNION) ? "union"
518: : "enum",
519: sp->s_id);
520: return 4;
521: }
522: /* T_NONE, T_PTR, T_VOID */
523: cbotch("aligntype type=%d", type);
524: }
525:
526: /*
527: * Run down a struct INFO list to find alignment type.
528: */
529: int
530: saligntype(ip) register INFO *ip;
531: {
532: register int i, j, max, n;
533:
534: if (alignment != 0)
535: return alignment;
536: n = ip->i_nsp; /* number of members */
537: for (i = max = 0; i < n; i++) {
538: j = aligntype(ip->i_sp[i]);
539: if (j > max)
540: max = j;
541: }
542: return max;
543: }
544:
545: /*
546: * Given a field type, return an appropriate alignment type.
547: */
548: int
549: faligntype(t) register int t;
550: {
551: if (t <= T_ULONG && t != T_PTR)
552: return mysizes[t];
553: cbotch("faligntype %d", t);
554: }
555:
556: /*
557: * Check object sizes for overflow.
558: */
559: sizeof_t
560: szcheck(n, a, s) sizeof_t n; int a; char *s;
561: {
562: return n;
563: }
564:
565: #if FOLD_DOUBLES
566: /*
567: * Convert DCON to/from host double.
568: * Used by the double constant folder in n0/fold.c.
569: * Assumes host fp representation == target fp representation!
570: * The byte orders of the double and DCON are reversed.
571: */
572: double
573: dval_to_d(tp) TREE *tp;
574: {
575: double d;
576: register char *src, *dst;
577:
578: for (src = tp->t_dval, dst = ((char *)&d) + sizeof(d) - 1; dst >= &d; )
579: *dst-- = *src++;
580: return d;
581: }
582:
583: void
584: d_to_dval(tp, d) TREE *tp; double d;
585: {
586: register char *src, *dst;
587:
588: for (dst = tp->t_dval, src = ((char *)&d) + sizeof(d) - 1; src >= &d; )
589: *dst++ = *src--;
590: }
591: #endif
592:
593: /* end of n0/i386/bind.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.