|
|
1.1 root 1: /* @(#) optim.c: 1.3 1/12/84 */
2:
3: # include "mfile1.h"
4:
5: # define ISCON(p) (p->in.op==ICON)
6:
7: int opdebug = 0;
8: NODE *doptim();
9:
10: NODE *
11: aadjust( p, adj )
12: register NODE *p;
13: register adj;
14: {
15: /* try to adjust p by adj bits */
16: register NODE *q;
17: adj = BITOOR(adj);
18: switch( p->tn.op )
19: {
20: case ICON:
21: p->tn.lval += adj;
22: return( p );
23: default:
24: /* construct a + node */
25: mkplus:
26: return( block( PLUS, p, bcon(adj), p->fn.type,
27: p->fn.cdim, p->fn.csiz ) );
28: case PLUS:
29: q = p->in.right;
30: if( q->tn.op != ICON ) goto mkplus;
31: q->tn.lval += adj;
32: return( p );
33: case MINUS:
34: q = p->in.right;
35: if( q->tn.op != ICON ) goto mkplus;
36: q->tn.lval -= adj;
37: return( p );
38: }
39: }
40:
41: adjust( p, adj )
42: register NODE *p;
43: register adj;
44: {
45: /* handle adjustment of scalars by adj bits */
46:
47: switch( p->tn.op )
48: {
49: case NAME:
50: case VAUTO:
51: case VPARAM:
52: p->tn.lval += BITOOR(adj);
53: return( 1 );
54: case STAR:
55: p->in.left = aadjust( p->in.left, adj );
56: return( 1 );
57: default:
58: return( 0 );
59: }
60: }
61:
62: # ifdef NOSIMPSTR
63: # ifndef MYSIMPSTR
64: simpstr( d, s )
65: {
66: return( STRTY );
67: }
68: # endif
69: # else
70: TWORD
71: simpstr( d, s )
72: {
73: /* return STRTY if not, and CHAR, INT, SHORT, or LONG if simple */
74: register sz, al;
75:
76: sz = tsize( STRTY, d, s );
77: al = talign( STRTY, s );
78: if( sz == SZINT /*&& !( al % ALINT)*/ ) return( INT );
79: else if( sz == SZCHAR /*&& !( al % ALCHAR)*/ ) return( CHAR );
80: else if( sz == SZLONG /*&& !( al % ALLONG)*/ ) return( LONG );
81: else if( sz == SZSHORT /*&& !( al % ALSHORT)*/ ) return( SHORT );
82: return( STRTY );
83: }
84: # endif
85:
86: tydown( p )
87: NODE *p;
88: {
89: /* reflect the type of p downwards, as appropriate */
90: /* the type is typically getting smaller */
91: /* returns 1 if it makes a real change */
92:
93: TWORD t;
94: NODE *l, *r;
95: int flag;
96:
97: #ifndef NODBG
98: if( opdebug )
99: {
100: printf( "tydown(%d) called with:\n", p-node );
101: eprint( p );
102: }
103: #endif
104: t = p->tn.type;
105: if( ISPTR(t) || ISARY(t) ) return(0);
106:
107: /* work these types down into the tree */
108:
109: flag = 0;
110:
111: switch( p->tn.op )
112: {
113:
114: case AND:
115: case OR:
116: case PLUS:
117: case MINUS:
118: case ER:
119: case COMOP:
120: #ifndef NODBG
121: if( opdebug )
122: {
123: printf( "tydown:\n" );
124: eprint( p );
125: }
126: #endif
127: r = p->in.right;
128: if( bigsize(r->tn.type) > bigsize(p->tn.type ) )
129: {
130: r = makety( r, t, 0, (int) t );
131: tydown( r );
132: p->in.right = doptim( r );
133: #ifndef NODBG
134: if( opdebug )
135: {
136: printf( "tydown(%d), after doptim(R):\n",
137: p-node );
138: eprint(p);
139: }
140: #endif
141: flag = 1;
142: }
143: if( p->tn.op == COMOP ) return( flag );
144: /* FALLTHRU */
145:
146: case UNARY MINUS:
147: case COMPL:
148: l = p->in.left;
149: if( bigsize(l->tn.type) > bigsize(p->tn.type ) )
150: {
151: l = makety( l, t, 0, (int) t );
152: tydown( l );
153: p->in.left = doptim( l );
154: #ifndef NODBG
155: if( opdebug )
156: {
157: printf( "tydown(%d), after doptim(L):\n",
158: p-node );
159: eprint(p);
160: }
161: #endif
162: flag = 1;
163: }
164: return(flag);
165: }
166: return( 0 ); /* no change */
167: }
168:
169: # ifndef MYCONVERT
170: NODE *
171: sconvert( p )
172: register NODE *p;
173: {
174: register TWORD t, lt;
175: register NODE *l;
176: register o;
177:
178: /* optimize CONV nodes */
179: /* the unsigned-ness is ignored */
180: /* if the CONV involves floats or doubles, retain unless null */
181: /* if the CONV makes things bigger, retain */
182: /* if the CONV keeps things the same size, just paint the type */
183: /* if the CONV makes things smaller, adjust the addressing with
184: ** memory references, and paint the new type
185: */
186: /* if a pointer is being converted, convert as if it were PTRTYPE */
187: /* finally, if CONV converts a constant, do it in place */
188: again:
189: #ifndef NODBG
190: if( opdebug )
191: {
192: printf( "sconvert(%d) called:\n", p-node );
193: eprint( p );
194: }
195: #endif
196: if( p->tn.op != CONV ) cerror( "sconvert" );
197: l = p->in.left;
198: t = p->tn.type;
199: lt = l->tn.type;
200: o = l->tn.op;
201:
202: if( o == FCON )
203: {
204: /* for a floating point const, paint type,
205: ** round when it is output */
206: if( t == FLOAT || t == DOUBLE ) goto paint;
207: /* otherwise, convert it to long and treat as long conversion */
208: l->tn.op = ICON;
209: l->tn.lval = l->fpn.dval; /* MACHINE-DEPENDENT CONVERSION */
210: l->tn.rval = NONAME;
211: goto icon;
212: }
213:
214: if( o==CONV && cbigger( l ) )
215: {
216: merge:
217: p->in.left = l->in.left;
218: l->tn.op = FREE;
219: tydown( p );
220: goto again;
221: }
222: if( t == lt && (t == DOUBLE || t == FLOAT) )
223: goto paint; /* float over float, double over double */
224: if( t==FLOAT || t==DOUBLE || t == VOID
225: || lt==FLOAT || lt==DOUBLE ) return( p );
226:
227: if( ISUNSIGNED(t) ) t = DEUNSIGN(t);
228: if( ISUNSIGNED(lt) ) lt = DEUNSIGN(lt);
229: if( ISPTR(lt) )
230: # ifdef MEMONLY
231: if( o==STAR || o==NAME || o==VAUTO || o==VPARAM )
232: # endif
233: lt = PTRTYPE;
234: if( t == lt ) goto paint;
235: if( ISPTR(lt) || ISARY(lt) ) return(p);
236:
237: if( o == ICON )
238: {
239: icon:
240: l->tn.lval = ccast( l->tn.lval, p->tn.type );
241: paint:
242: l->tn.type = p->tn.type;
243: l->fn.csiz = p->fn.csiz;
244: l->fn.cdim = p->fn.cdim;
245: p->tn.op = FREE;
246: if( tydown(l) )
247: {
248: l = doptim(l);
249: }
250: return( l );
251: }
252: if( cbigger(p) ) return( p );
253: /* p makes things smaller */
254: if( o==CONV )
255: {
256: /* two conversions in a row: the second makes things smaller */
257: /* make them into one */
258: goto merge;
259: }
260: if( o==STAR || o==NAME || o==VAUTO || o==VPARAM )
261: {
262: /* memory reference: determine the adjustment */
263: # ifdef RTOLBYTES
264: # ifdef LOWINT
265: if( lt == LONG ) if( !adjust( l, LOWINT )) cerror( "adj" );
266: # endif
267: # else
268: register adj = 0;
269: if( lt == LONG ) adj = SZLONG;
270: else if( lt == INT ) adj = SZINT;
271: else if( lt == SHORT ) adj = SZSHORT;
272: else cerror( "sconv:lt 0%o", lt );
273: if( t == INT ) adj -= SZINT;
274: else if( t == SHORT ) adj -= SZSHORT;
275: else if( t == CHAR ) adj -= SZCHAR;
276: else cerror( "sconv:t 0%o", t );
277: # ifdef LOWINT
278: if( lt == LONG ) adj += LOWINT;
279: # endif
280: if( adj ) if( !adjust( l, adj ) ) cerror( "adj1" );
281: # endif
282: }
283:
284: /* other cases are where it is computed into a reg; */
285: /* simply paint the type */
286: /* must avoid clobbering the type for assignment nodes */
287: /* however, we must copy (e.g., apply the CONV) for register vars */
288: /* also, can't paint type over fields */
289: if( o == REG || asgop(o) || o == FLD ) return( p );
290: goto paint;
291: }
292: # endif
293:
294: NODE *
295: pvconvert( p )
296: register NODE *p;
297: {
298: /* p is a CONV node; convert */
299: /* this does something only when the descendent is not a ptr */
300: register NODE *l;
301: register int o;
302: l = p->in.left;
303: if( ISPTR( l->tn.type ) ) return( clocal(p) );
304: # ifdef MEMONLY
305: o = l->tn.op;
306: if( o==STAR || o==NAME || o==VAUTO || o==VPARAM || o==ICON )
307: # endif
308: {
309: /* optimize this reference */
310: /* sconvert and optimize to PTRTYPE */
311: l = makety( l, PTRTYPE, 0, PTRTYPE );
312: if( l->tn.op == CONV ) l = sconvert( l );
313: l->tn.type = p->tn.type;
314: l->fn.cdim = p->fn.cdim;
315: l->fn.csiz = p->fn.csiz;
316: p->tn.op = FREE;
317: p = l;
318: }
319: return( clocal(p) );
320: }
321:
322: NODE *
323: fortarg( p )
324: register NODE *p;
325: {
326: /* fortran function arguments */
327:
328: if( p->in.op == CM )
329: {
330: p->in.left = fortarg( p->in.left );
331: p->in.right = fortarg( p->in.right );
332: return(p);
333: }
334: while( ISPTR(p->in.type) )
335: {
336: p = buildtree( STAR, p, NIL );
337: }
338: return( optim(p) );
339: }
340:
341: /* mapping relationals when the sides are reversed */
342: short revrel[] =
343: {
344: EQ, NE, GE, GT, LE, LT, UGE, UGT, ULE, ULT
345: };
346:
347: #ifndef NODBG
348: #define REPORT(x) if(opdebug){printf( "optim did\n"); eprint(x);}
349: #else
350: # define REPORT(x)
351: #endif
352: NODE *
353: doptim(p)
354: register NODE *p;
355: {
356: /* local optimizations, most of which are machine independent */
357: /* doptim is called for each node by optim; it assumes that
358: ** the children of p are already optimized
359: */
360: /* p is not a leaf */
361: register NODE *l, *r, *sp;
362: register o, i;
363: register TWORD t;
364:
365: #ifndef NODBG
366: if( opdebug )
367: {
368: printf( "doptim called on:\n" );
369: eprint(p);
370: }
371: #endif
372:
373: if( (t=BTYPE(p->in.type))==ENUMTY || t==MOETY ) econvert(p);
374: switch( optype( o = p->tn.op ) )
375: {
376: case BITYPE:
377: r = p->in.right;
378: /* FALLTHRU */
379: case UTYPE:
380: l = p->in.left;
381: break;
382: case LTYPE:
383: /* nothing more to do (after doing the enum stuff) */
384: return( p );
385: }
386: sp = conval( p );
387: /* return only if conval did something */
388: if( sp != p ) return( doptim(sp) );
389: #ifndef NODBG
390: if( opdebug )
391: {
392: printf( "doptim works on:\n" );
393: eprint(p);
394: }
395: #endif
396: switch(o)
397: {
398: case COMOP: /* maybe simpstr changed the type of the right */
399: if(p->in.type != r->in.type) {
400: p->in.type = r->in.type;
401: /* anything else? */
402: REPORT(p);
403: }
404: return(p);
405: case CONV:
406: /* someday, make pvconvert and sconvert the same */
407: return( ISPTR(p->tn.type)?pvconvert(p):sconvert(p) );
408: case ASG PLUS:
409: case ASG MINUS:
410: case ASG AND:
411: case ASG OR:
412: case ASG ER:
413: case ASG LS:
414: case ASG RS:
415: case ASG MUL:
416: case ASG DIV:
417: case ASG MOD:
418: /* if conversion ops on the lhs, transfer them to the rhs */
419: t = l->in.type;
420:
421: /* (CONV A) op= B into A op= (CONV B)
422: ** this only holds if the result depends only on the
423: ** low order part of B (e.g., that part of B that
424: ** is the width of A
425: ** this is not true for /=, %=, or floats */
426:
427: if( l->tn.op == CONV && t!=FLOAT && t!=DOUBLE
428: && o!=ASG DIV && o != ASG MOD )
429: {
430: p->in.left = l->in.left;
431: l->tn.op = FREE;
432: l = l->in.left;
433: r = makety( r, p->in.type, p->fn.cdim, p->fn.csiz );
434: p->in.right = doptim( r );
435: }
436: if( !nncon(r) ) break; /* no more optimization */
437: /* get rid of 0 ops that don't change anything... */
438: if( !r->tn.lval && (o==ASG PLUS || o==ASG MINUS || o==ASG OR ||
439: o==ASG ER || o==ASG LS || o==ASG RS) )
440: {
441: /* the answer is the lhs */
442: goto bless;
443: }
444: if( r->tn.lval == 1 && (o==ASG MUL || o==ASG DIV) )
445: {
446: /* the answer is the lhs */
447: goto bless;
448: }
449: if( (i = ispow2( r->tn.lval ))>=0 && o==ASG MUL )
450: {
451: o = p->in.op = ASG LS;
452: r->tn.lval = i;
453: }
454: break;
455: case LS:
456: case RS:
457: if( !nncon(r) || r->tn.lval )
458: break; /* do nothing */
459: goto bless; /* shifts by 0 */
460: case FORTCALL:
461: p->in.right = fortarg( r );
462: break;
463: case UNARY AND:
464: switch( l->tn.op )
465: {
466: case STAR:
467: /* fake up to use setuleft */
468: l->tn.op = FREE;
469: l=l->in.left;
470: goto setuleft;
471: case VAUTO:
472: case VPARAM:
473: case TEMP:
474: /* the next two lines come from short structs */
475: case CALL:
476: case UNARY CALL:
477: break;
478:
479: case RNODE:
480: # ifdef ARGSRET
481: /* RNODE disappears if structure simple */
482: if( simpstr( p->fn.cdim, p->fn.csiz ) == STRTY )
483: {
484: /* complicated: make it look like first arg */
485: l->tn.op = VPARAM;
486: l->tn.lval = BITOOR(ARGINIT);
487: l->tn.rval = NONAME;
488: }
489: break;
490: #else
491: # ifdef STATSRET
492: /* simple structures will disappear */
493: if( simpstr( p->fn.cdim, p->fn.csiz ) != STRTY ) break;
494: /* otherwise, make & RNODE into ICON for static area */
495: l->tn.rval = -strftn;
496: # else
497: break; /* & of RNODE is just fine */
498: #endif
499: #endif
500: case NAME:
501: # ifdef ANDABLE
502: if( !ANDABLE(l) ) return(p);
503: # endif
504: l->tn.op = ICON;
505: setuleft:
506: /* set the type of lhs with the type of the top */
507: l->in.type = p->in.type;
508: l->fn.cdim = p->fn.cdim;
509: l->fn.csiz = p->fn.csiz;
510: p->in.op = FREE;
511: REPORT(l);
512: return( l );
513: default:
514: cerror( "& error" );
515: }
516: break;
517: case STCALL:
518: case UNARY STCALL:
519: /* use l in case return type overwritten */
520: t = simpstr( l->fn.cdim, l->fn.csiz );
521: if( t != STRTY )
522: {
523: /* take some care to keep the types OK */
524: /* the type of the return might well have been
525: ** overwritten by (say) a structure reference
526: */
527: /* MAY NOT BE QUITE RIGHT IF TWO FLAVORS OF PTR */
528: l = p;
529: p->tn.type = DECREF( p->tn.type );
530: p = buildtree( UNARY AND, l, NIL );
531: if( o == STCALL ) l->tn.op = CALL;
532: else l->tn.op = UNARY CALL;
533: l->fn.type = l->fn.csiz = t;
534: l->fn.cdim = 0;
535: }
536: break;
537: case STAR:
538: if( p->tn.type == STRTY || p->tn.type == UNIONTY )
539: {
540: p->tn.op = FREE;
541: REPORT(l);
542: return( l );
543: }
544: if( l->tn.op == UNARY AND && !callop(l->in.left->tn.op) )
545: {
546: /* & of call used in structure optimization */
547: /* fake up to use setuleft */
548: l->tn.op = FREE;
549: l = l->in.left;
550: goto setuleft;
551: }
552: if( l->tn.op != ICON ) break;
553: l->tn.op = NAME;
554: goto setuleft;
555: case MINUS:
556: if( !nncon(r) ) break;
557: r->tn.lval = - r->tn.lval;
558: o = p->in.op = PLUS;
559: case MUL:
560: case PLUS:
561: case AND:
562: case OR:
563: case ER:
564: /* commutative ops; for now, just collect constants */
565: /* someday, do it right */
566: if( o==r->tn.op || nncon(l) || ( ISCON(l) && !ISCON(r) ) )
567: {
568: /* make ops tower to the left, not the right */
569: /* also, put constants on the right */
570: sp = l;
571: l = p->in.left = r;
572: r = p->in.right = sp;
573: }
574: /* do (A + C1) + C2, etc. */
575: /* the number of special cases is horrifying */
576: /* many bugs have been found here; this code is very cautious */
577: /* (A + C1) + C2, where C2 can be a ptr, C1 not */
578: if( o==PLUS && l->tn.op==PLUS && ISCON(r) &&
579: nncon(l->in.right) )
580: {
581: p->in.left = l->in.left;
582: l->tn.op = FREE;
583: l = l->in.right;
584: r->tn.lval += l->tn.lval;
585: l->tn.op = FREE;
586: return( doptim( p ) );
587: }
588: /* (A + C1) + C2, where C1 can be a ptr, C2 not */
589: if( o==PLUS && l->tn.op==PLUS && nncon(r) &&
590: ISCON(l->in.right) )
591: {
592: l->in.right->tn.lval += r->tn.lval;
593: goto bless; /* return l as the result */
594: }
595: /* (A - C1) + C2, where C2 can be a ptr, C1 not */
596: if( o==PLUS && l->tn.op==MINUS && ISCON(r) &&
597: nncon(l->in.right) )
598: {
599: p->in.left = l->in.left;
600: l->tn.op = FREE;
601: l = l->in.right;
602: r->tn.lval -= l->tn.lval;
603: l->tn.op = FREE;
604: return( doptim( p ) );
605: }
606: /* (&A)+C */
607: if( o==PLUS && l->tn.op == UNARY AND && ISCON(r) )
608: {
609: switch( l->in.left->tn.op )
610: {
611: case NAME:
612: case VPARAM:
613: case VAUTO:
614: l->in.left->tn.lval += r->tn.lval;
615: goto bless;
616: }
617: }
618: /* change muls to shifts */
619: if( o==MUL && nncon(r) && (i=ispow2(r->tn.lval))>=0)
620: {
621: if( i == 0 )
622: {
623: /* multiplication by 1 */
624: bless:
625: /* return l, with the type of p */
626: l = makety( l, p->tn.type, p->fn.cdim,
627: p->fn.csiz );
628: r->tn.op = FREE;
629: p->tn.op = FREE;
630: /* if a conversion op was added, optimize */
631: l = doptim( l );
632: #ifndef NODBG
633: if( opdebug )
634: {
635: printf( "optim replaces op1 (%d) by:\n",
636: p-node );
637: eprint(l);
638: }
639: #endif
640: return( l );
641: }
642: o = p->in.op = LS;
643: r->tn.lval = i;
644: }
645: /* change +'s of negative consts back to - */
646: if( o==PLUS && nncon(r) && r->tn.lval<0 )
647: {
648: r->tn.lval = -r->tn.lval;
649: o = p->in.op = MINUS;
650: }
651: if( nncon(r) && !r->tn.lval && (o==PLUS||o==MINUS) )
652: {
653: /* get rid of add or subtract of 0 */
654: goto bless;
655: }
656: # ifdef PTRLEFT
657: if( o==PLUS && ISPTR(p->tn.type) && ISPTR(r->tn.type)
658: # ifdef CONSRIGHT
659: && r->tn.op != ICON
660: # endif
661: )
662: {
663: sp = l;
664: p->in.left = r;
665: p->in.right = sp;
666: }
667: # endif
668: # ifdef PTRRIGHT
669: if( o==PLUS && ISPTR(p->tn.type) && ISPTR(l->tn.type)
670: # ifdef CONSRIGHT
671: && r->tn.op != ICON
672: # endif
673: )
674: {
675: sp = l;
676: p->in.left = r;
677: p->in.right = sp;
678: }
679: # endif
680: break;
681: case DIV:
682: if( nncon( r ) && r->tn.lval == 1 ) goto bless;
683: break;
684: case EQ:
685: case NE:
686: case LT:
687: case LE:
688: case GT:
689: case GE:
690: case ULT:
691: case ULE:
692: case UGT:
693: case UGE:
694: if( ISCON(l) && !ISCON(r) )
695: {
696: /* exchange operands */
697: p->in.op = revrel[p->in.op - EQ ];
698: sp = l;
699: l = p->in.left = r;
700: r = p->in.right = sp;
701: }
702: break;
703: case STASG:
704: if( (t=simpstr( p->fn.cdim, p->fn.csiz ) ) != STRTY )
705: {
706: /* rewrite = as simpler */
707: if( ISPTR(r->tn.type) )
708: {
709: r = buildtree( STAR, r, NIL );
710: r->fn.type = r->fn.csiz = t;
711: r->fn.cdim = 0;
712: p->in.right = r = doptim( r );
713: }
714: l = buildtree( STAR, l, NIL );
715: l->fn.type = l->fn.csiz = t;
716: l->fn.cdim = 0;
717: p->in.left = l = doptim( l );
718: p->fn.type = p->fn.csiz = t;
719: p->fn.cdim = 0;
720: p->fn.op = ASSIGN;
721: return( p );
722: }
723: case STARG:
724: if( (t=simpstr( p->fn.cdim, p->fn.csiz ) ) != STRTY )
725: {
726: /* rewrite as simpler */
727: if( ISPTR(l->fn.type) )
728: {
729: l = buildtree( STAR, l, NIL );
730: l->fn.type = l->fn.csiz = t;
731: l->fn.cdim = 0;
732: p->in.left = l = doptim( l );
733: }
734: p->fn.type = p->fn.csiz = (t==LONG ? LONG : INT);
735: p->fn.cdim = 0;
736: p->fn.op = FUNARG;
737: return( p );
738: }
739: # ifdef ENDSTRUCT
740: p->in.left = aadjust( l, p->stn.stsize );
741: # endif
742: break;
743: }
744: return(p);
745: }
746:
747: NODE *
748: optim( p )
749: register NODE *p;
750: {
751: switch( optype( p->tn.op ) )
752: {
753: case BITYPE:
754: p->in.right = optim( p->in.right );
755: /* FALLTHRU */
756: case UTYPE:
757: p->in.left = optim( p->in.left );
758: }
759: return( doptim( p ) );
760: }
761:
762: ispow2( c )
763: register CONSZ c;
764: {
765: register i;
766: if( c <= 0 || (c&(c-1)) ) return(-1);
767: for( i=0; c>1; ++i) c >>= 1;
768: return(i);
769: }
770:
771: nncon( p )
772: register NODE *p;
773: {
774: /* is p a constant without a name */
775: return( p->tn.op == ICON && p->tn.rval == NONAME && !ISPTR(p->tn.type));
776: }
777:
778: /* some routines for debugging and tree transformation */
779: #ifndef MYOFFCON
780: NODE *
781: offcon( off, t, d, s )
782: OFFSZ off;
783: TWORD t;
784: {
785: /* return a node, for structure references, which is suitable for
786: ** being added to a pointer of type t, in order to be off bits offset
787: ** into a structure
788: */
789: register NODE *p;
790:
791: /* t, d, and s are the type, dimension offset, and size offset */
792: /* in general they may be necessary for offcon */
793: p = bcon(0);
794: p->tn.lval = BITOOR(off);
795: p->fn.type = p->fn.csiz = PTRTYPE;
796: return(p);
797: }
798: # endif
799:
800: bccode()
801: {
802: /* called just before executing code */
803: /* beware: called several times if there is auto. initialization */
804: # ifdef MYBCCODE
805: MYBCCODE;
806: # endif
807: p2bbeg( autooff, regvar );
808: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.