示例#1
0
文件: local2.c 项目: sambuc/netbsd
static void
starg(NODE *p)
{
	int sz = p->n_stsize;
	int subsz = (p->n_stsize + 3) & ~3;
	int fr, tr, cr;

	fr = regno(getlr(p, 'L')); /* from reg (struct pointer) */
	cr = regno(getlr(p, '1')); /* count reg (number of words) */
	tr = regno(getlr(p, '2')); /* to reg (stack) */

	/* Sub from stack and put in toreg */
	printf("	sub.l #%d,%%sp\n", subsz);
	printf("	move.l %%sp,%s\n", rnames[tr]);

	/* Gen an even copy start */
	if (sz & 1)
		expand(p, INBREG, "	move.b (A2)+,(AL)+\n");
	if (sz & 2)
		expand(p, INBREG, "	move.w (A2)+,(AL)+\n");
	sz -= (sz & ~3);
	
	/* if more than 4 words, use loop, otherwise output instructions */
	if (sz > 16) {
		printf("	move.l #%d,%s\n", sz/4, rnames[cr]);
		expand(p, INBREG, "1:	move.l (A2)+,(AL)+\n");
		expand(p, INBREG, "	dec.l A1\n");
		expand(p, INBREG, "	jne 1b\n");
	} else {
		if (sz > 12)
			expand(p, INBREG, "	move.l (A2)+,(AL)+\n"), sz -= 4;
		if (sz > 8)
			expand(p, INBREG, "	move.l (A2)+,(AL)+\n"), sz -= 4;
		if (sz > 4)
			expand(p, INBREG, "	move.l (A2)+,(AL)+\n"), sz -= 4;
		if (sz == 4)
			expand(p, INBREG, "	move.l (A2)+,(AL)+\n");
	}
}
示例#2
0
void
zzzcode(NODE *p, int c)
{
	TWORD t = p->n_type;
	char *s;

	switch (c) {
	case 'L':
		t = p->n_left->n_type;
		/* FALLTHROUGH */
	case 'A':
		s = (t == CHAR || t == UCHAR ? "b" :
		    t == SHORT || t == USHORT ? "w" : 
		    t == FLOAT ? "s" :
		    t == DOUBLE ? "d" :
		    t == LDOUBLE ? "x" : "l");
		printf("%s", s);
		break;

	case 'B':
		if (p->n_qual)
			printf("	add.l #%d,%%sp\n", (int)p->n_qual);
		break;

	case 'C': /* jsr or bsr.l XXX - type of CPU? */
		printf("%s", kflag ? "bsr.l" : "jsr");
		break;

	case 'F': /* Emit float branches */
		switch (p->n_op) {
		case GT: s = "fjnle"; break;
		case GE: s = "fjnlt"; break;
		case LE: s = "fjngt"; break;
		case LT: s = "fjnge"; break;
		case NE: s = "fjne"; break;
		case EQ: s = "fjeq"; break;
		default: comperr("ZF"); s = 0;
		}
		printf("%s " LABFMT "\n", s, p->n_label);
		break;

	case 'P':
		printf("	lea -%d(%%fp),%%a0\n", stkpos);
		break;

	case 'Q': /* struct assign */
		printf("	move.l %d,-(%%sp)\n", 
		    attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0));
		expand(p, INAREG, "	move.l AR,-(%sp)\n");
		expand(p, INAREG, "	move.l AL,-(%sp)\n");
		printf("	jsr memcpy\n");
		printf("	add.l #12,%%sp\n");
		break;

	case 'S': /* struct arg */
		starg(p);
		break;

	case '2':
		if (regno(getlr(p, '2')) != regno(getlr(p, 'L')))
			expand(p, INAREG, "	fmove.x AL,A2\n");
		break;

	default:
		comperr("zzzcode %c", c);
	}
}
示例#3
0
文件: local2.c 项目: didickman/pcc
void
zzzcode(NODE *p, int c)
{
	NODE *l;
	int pr, lr;
	char *ch;

	switch (c) {
	case 'A': /* swap st0 and st1 if right is evaluated second */
		if ((p->n_su & DORIGHT) == 0) {
			if (logop(p->n_op))
				printf("	fxch\n");
			else
				printf("r");
		}
		break;

	case 'C':  /* remove from stack after subroutine call */
#ifdef notyet
		if (p->n_left->n_flags & FSTDCALL)
			break;
#endif
		pr = p->n_qual;
		if (p->n_op == STCALL || p->n_op == USTCALL)
			pr += 4;
		if (p->n_flags & FFPPOP)
			printf("	fstp	%%st(0)\n");
		if (p->n_op == UCALL)
			return; /* XXX remove ZC from UCALL */
		if (pr)
			printf("	addl $%d, %s\n", pr, rnames[ESP]);
		break;

	case 'D': /* Long long comparision */
		twollcomp(p);
		break;

	case 'F': /* Structure argument */
		if (p->n_stalign != 0) /* already on stack */
			starg(p);
		break;

	case 'G': /* Floating point compare */
		fcomp(p);
		break;

	case 'H': /* assign of longlong between regs */
		rmove(DECRA(p->n_right->n_reg, 0),
		    DECRA(p->n_left->n_reg, 0), LONGLONG);
		break;

	case 'I': /* float casts */
		fcast(p);
		break;

	case 'J': /* convert unsigned long long to floating point */
		ulltofp(p);
		break;

	case 'K': /* Load longlong reg into another reg */
		rmove(regno(p), DECRA(p->n_reg, 0), LONGLONG);
		break;

	case 'M': /* Output sconv move, if needed */
		l = getlr(p, 'L');
		/* XXX fixneed: regnum */
		pr = DECRA(p->n_reg, 0);
		lr = DECRA(l->n_reg, 0);
		if ((pr == AL && lr == EAX) || (pr == BL && lr == EBX) ||
		    (pr == CL && lr == ECX) || (pr == DL && lr == EDX))
			;
		else
			printf("	movb %%%cl,%s\n",
			    rnames[lr][2], rnames[pr]);
		l->n_rval = l->n_reg = p->n_reg; /* XXX - not pretty */
		break;

	case 'N': /* output extended reg name */
		printf("%s", rnames[getlr(p, '1')->n_rval]);
		break;

	case 'O': /* print out emulated ops */
		pr = 16;
		if (p->n_op == RS || p->n_op == LS) {
			llshft(p);
			break;
		} else if (p->n_op == MUL) {
			printf("\timull %%ecx, %%edx\n");
			printf("\timull %%eax, %%esi\n");
			printf("\taddl %%edx, %%esi\n");
			printf("\tmull %%ecx\n");
			printf("\taddl %%esi, %%edx\n");
			break;
		}
		expand(p, INCREG, "\tpushl UR\n\tpushl AR\n");
		expand(p, INCREG, "\tpushl UL\n\tpushl AL\n");
		if (p->n_op == DIV && p->n_type == ULONGLONG) ch = "udiv";
		else if (p->n_op == DIV) ch = "div";
		else if (p->n_op == MOD && p->n_type == ULONGLONG) ch = "umod";
		else if (p->n_op == MOD) ch = "mod";
		else ch = 0, comperr("ZO");
#ifdef ELFABI
		printf("\tcall " EXPREFIX "__%sdi3%s\n\taddl $%d,%s\n",
			ch, (kflag ? "@PLT" : ""), pr, rnames[ESP]);
#else
		printf("\tcall " EXPREFIX "__%sdi3\n\taddl $%d,%s\n",
			ch, pr, rnames[ESP]);
#endif
                break;

	case 'P': /* push hidden argument on stack */
		printf("\tleal -%d(%%ebp),", stkpos);
		adrput(stdout, getlr(p, '1'));
		printf("\n\tpushl ");
		adrput(stdout, getlr(p, '1'));
		putchar('\n');
		break;

	case 'Q': /* emit struct assign */
		/*
		 * With <= 16 bytes, put out mov's, otherwise use movsb/w/l.
		 * esi/edi/ecx are available.
		 * XXX should not need esi/edi if not rep movsX.
		 * XXX can save one insn if src ptr in reg.
		 */
		switch (p->n_stsize) {
		case 1:
			expand(p, INAREG, "	movb (%esi),%cl\n");
			expand(p, INAREG, "	movb %cl,AL\n");
			break;
		case 2:
			expand(p, INAREG, "	movw (%esi),%cx\n");
			expand(p, INAREG, "	movw %cx,AL\n");
			break;
		case 4:
			expand(p, INAREG, "	movl (%esi),%ecx\n");
			expand(p, INAREG, "	movl %ecx,AL\n");
			break;
		default:
			expand(p, INAREG, "	leal AL,%edi\n");
			if (p->n_stsize <= 16 && (p->n_stsize & 3) == 0) {
				printf("	movl (%%esi),%%ecx\n");
				printf("	movl %%ecx,(%%edi)\n");
				printf("	movl 4(%%esi),%%ecx\n");
				printf("	movl %%ecx,4(%%edi)\n");
				if (p->n_stsize > 8) {
					printf("	movl 8(%%esi),%%ecx\n");
					printf("	movl %%ecx,8(%%edi)\n");
				}
				if (p->n_stsize == 16) {
					printf("\tmovl 12(%%esi),%%ecx\n");
					printf("\tmovl %%ecx,12(%%edi)\n");
				}
			} else {
				if (p->n_stsize > 4) {
					printf("\tmovl $%d,%%ecx\n",
					    p->n_stsize >> 2);
					printf("	rep movsl\n");
				}
				if (p->n_stsize & 2)
					printf("	movsw\n");
				if (p->n_stsize & 1)
					printf("	movsb\n");
			}
			break;
		}
		break;

	case 'S': /* emit eventual move after cast from longlong */
		pr = DECRA(p->n_reg, 0);
		lr = p->n_left->n_rval;
		switch (p->n_type) {
		case CHAR:
		case UCHAR:
			if (rnames[pr][2] == 'l' && rnames[lr][2] == 'x' &&
			    rnames[pr][1] == rnames[lr][1])
				break;
			if (rnames[lr][2] == 'x') {
				printf("\tmovb %%%cl,%s\n",
				    rnames[lr][1], rnames[pr]);
				break;
			}
			/* Must go via stack */
			expand(p, INAREG, "\tmovl AL,A2\n");
			expand(p, INBREG, "\tmovb A2,A1\n");
#ifdef notdef
			/* cannot use freetemp() in instruction emission */
			s = BITOOR(freetemp(1));
			printf("\tmovl %%e%ci,%d(%%ebp)\n", rnames[lr][1], s);
			printf("\tmovb %d(%%ebp),%s\n", s, rnames[pr]);
#endif
			break;

		case SHORT:
		case USHORT:
			if (rnames[lr][1] == rnames[pr][2] &&
			    rnames[lr][2] == rnames[pr][3])
				break;
			printf("\tmovw %%%c%c,%%%s\n",
			    rnames[lr][1], rnames[lr][2], rnames[pr]+2);
			break;
		case INT:
		case UNSIGNED:
			if (rnames[lr][1] == rnames[pr][2] &&
			    rnames[lr][2] == rnames[pr][3])
				break;
			printf("\tmovl %%e%c%c,%s\n",
				    rnames[lr][1], rnames[lr][2], rnames[pr]);
			break;

		default:
			if (rnames[lr][1] == rnames[pr][2] &&
			    rnames[lr][2] == rnames[pr][3])
				break;
			comperr("SCONV2 %s->%s", rnames[lr], rnames[pr]);
			break;
		}
		break;

	default:
		comperr("zzzcode %c", c);
	}
示例#4
0
文件: local2.c 项目: JamesLinus/pcc
void
zzzcode(NODE *p, int c)
{
	struct attr *ap;
	NODE *l;
	int pr, lr;
	char *ch;

	switch (c) {
	case 'A': /* swap st0 and st1 if right is evaluated second */
		if ((p->n_su & DORIGHT) == 0) {
			if (logop(p->n_op))
				printf("	fxch\n");
			else
				printf("r");
		}
		break;

	case 'C':  /* remove from stack after subroutine call */
#ifdef GCC_COMPAT
		if (attr_find(p->n_left->n_ap, GCC_ATYP_STDCALL))
			break;
#endif
		pr = p->n_qual;
		if (attr_find(p->n_ap, ATTR_I386_FPPOP))
			printf("	fstp	%%st(0)\n");
		if (p->n_op == UCALL)
			return; /* XXX remove ZC from UCALL */
		if (pr)
			printf("	addl $%d, %s\n", pr, rnames[ESP]);
#if defined(os_openbsd)
		ap = attr_find(p->n_ap, ATTR_P2STRUCT);
		if (p->n_op == STCALL && (ap->iarg(0) == 1 ||
		    ap->iarg(0) == 2 || ap->iarg(0) == 4 || 
		    ap->iarg(0) == 8)) {
			/* save on stack */
			printf("\tmovl %%eax,-%d(%%ebp)\n", stkpos);
			printf("\tmovl %%edx,-%d(%%ebp)\n", stkpos+4);
			printf("\tleal -%d(%%ebp),%%eax\n", stkpos);
		}
#endif
		break;

	case 'D': /* Long long comparision */
		twollcomp(p);
		break;

	case 'F': /* Structure argument */
		starg(p);
		break;

	case 'G': /* Floating point compare */
		fcomp(p);
		break;

	case 'H': /* assign of longlong between regs */
		rmove(DECRA(p->n_right->n_reg, 0),
		    DECRA(p->n_left->n_reg, 0), LONGLONG);
		break;

	case 'I': /* float casts */
		fcast(p);
		break;

	case 'J': /* convert unsigned long long to floating point */
		ulltofp(p);
		break;

	case 'K': /* Load longlong reg into another reg */
		rmove(regno(p), DECRA(p->n_reg, 0), LONGLONG);
		break;

	case 'M': /* Output sconv move, if needed */
		l = getlr(p, 'L');
		/* XXX fixneed: regnum */
		pr = DECRA(p->n_reg, 0);
		lr = DECRA(l->n_reg, 0);
		if ((pr == AL && lr == EAX) || (pr == BL && lr == EBX) ||
		    (pr == CL && lr == ECX) || (pr == DL && lr == EDX))
			;
		else
			printf("	movb %%%cl,%s\n",
			    rnames[lr][2], rnames[pr]);
		l->n_rval = l->n_reg = p->n_reg; /* XXX - not pretty */
		break;

	case 'N': /* output extended reg name */
		printf("%s", rnames[getlr(p, '1')->n_rval]);
		break;

	case 'O': /* print out emulated ops */
		pr = 16;
		if (p->n_op == RS || p->n_op == LS) {
			llshft(p);
			break;
		} else if (p->n_op == MUL) {
			printf("\timull %%ecx, %%edx\n");
			printf("\timull %%eax, %%esi\n");
			printf("\taddl %%edx, %%esi\n");
			printf("\tmull %%ecx\n");
			printf("\taddl %%esi, %%edx\n");
			break;
		}
		expand(p, INCREG, "\tpushl UR\n\tpushl AR\n");
		expand(p, INCREG, "\tpushl UL\n\tpushl AL\n");
		if (p->n_op == DIV && p->n_type == ULONGLONG) ch = "udiv";
		else if (p->n_op == DIV) ch = "div";
		else if (p->n_op == MOD && p->n_type == ULONGLONG) ch = "umod";
		else if (p->n_op == MOD) ch = "mod";
		else ch = 0, comperr("ZO");
#ifdef ELFABI
		printf("\tcall " EXPREFIX "__%sdi3%s\n\taddl $%d,%s\n",
			ch, (kflag ? "@PLT" : ""), pr, rnames[ESP]);
#else
		printf("\tcall " EXPREFIX "__%sdi3\n\taddl $%d,%s\n",
			ch, pr, rnames[ESP]);
#endif
                break;

	case 'Q': /* emit struct assign */
		/*
		 * Put out some combination of movs{b,w,l}
		 * esi/edi/ecx are available.
		 */
		expand(p, INAREG, "	leal AL,%edi\n");
		ap = attr_find(p->n_ap, ATTR_P2STRUCT);
		if (ap->iarg(0) < 32) {
			int i = ap->iarg(0) >> 2;
			while (i) {
				expand(p, INAREG, "	movsl\n");
				i--;
			}
		} else {
示例#5
0
void
zzzcode(NODE *p, int c)
{
	NODE *l, *r;
	TWORD t;
	int m;
	char *ch;

	switch (c) {
	case 'N':  /* logical ops, turned into 0-1 */
		/* use register given by register 1 */
		cbgen( 0, m=getlab2());
		deflab( p->n_label );
		printf( "	clrl	%s\n", rnames[getlr( p, '1' )->n_rval] );
		deflab( m );
		return;

	case 'A': /* Assign a constant directly to a memory position */
		printf("\t");
		if (p->n_type < LONG || ISPTR(p->n_type))
			casg(p);
		else
			casg64(p);
		printf("\n");
		break;

	case 'B': /* long long compare */
		twollcomp(p);
		break;

	case 'C':	/* num words pushed on arg stack */
		printf("$%d", p->n_qual);
		break;

	case 'D':	/* INCR and DECR */
		zzzcode(p->n_left, 'A');
		printf("\n	");

#if 0
	case 'E':	/* INCR and DECR, FOREFF */
		if (p->n_right->n_lval == 1)
			{
			printf("%s", (p->n_op == INCR ? "inc" : "dec") );
			prtype(p->n_left);
			printf("	");
			adrput(stdout, p->n_left);
			return;
			}
		printf("%s", (p->n_op == INCR ? "add" : "sub") );
		prtype(p->n_left);
		printf("2	");
		adrput(stdout, p->n_right);
		printf(",");
		adrput(p->n_left);
		return;
#endif

	case 'F':	/* register type of right operand */
		{
		register NODE *n;
		register int ty;

		n = getlr( p, 'R' );
		ty = n->n_type;

		if (x2debug) printf("->%d<-", ty);

		if ( ty==DOUBLE) printf("d");
		else if ( ty==FLOAT ) printf("f");
		else printf("l");
		return;
		}

	case 'G': /* emit conversion instructions */
		sconv(p);
		break;

	case 'J': /* jump or ret? */
		{
			struct interpass *ip =
			    DLIST_PREV((struct interpass *)p2env.epp, qelem);
			if (ip->type != IP_DEFLAB ||
			    ip->ip_lbl != getlr(p, 'L')->n_lval)
				expand(p, FOREFF, "jbr	LL");
			else
				printf("ret");
		}
		break;

	case 'L':	/* type of left operand */
	case 'R':	/* type of right operand */
		{
		register NODE *n;

		n = getlr ( p, c);
		if (x2debug) printf("->%d<-", n->n_type);

		prtype(n);
		return;
		}

	case 'O': /* print out emulated ops */
		expand(p, FOREFF, "\tmovq	AR,-(%sp)\n");
		expand(p, FOREFF, "\tmovq	AL,-(%sp)\n");
		if (p->n_op == DIV && p->n_type == ULONGLONG) ch = "udiv";
		else if (p->n_op == DIV) ch = "div";
		else if (p->n_op == MOD && p->n_type == ULONGLONG) ch = "umod";
		else if (p->n_op == MOD) ch = "mod";
		else if (p->n_op == MUL) ch = "mul";
		else ch = 0, comperr("ZO %d", p->n_op);
		printf("\tcalls	$4,__%sdi3\n", ch);
		break;


	case 'Z':	/* complement mask for bit instr */
		printf("$%Ld", ~p->n_right->n_lval);
		return;

	case 'U':	/* 32 - n, for unsigned right shifts */
		t = DEUNSIGN(p->n_left->n_type);
		m = t == CHAR ? 8 : t == SHORT ? 16 : 32;
		printf("$" CONFMT, m - p->n_right->n_lval);
		return;

	case 'T':	/* rounded structure length for arguments */
		{
		int size;

		size = p->n_stsize;
		SETOFF( size, 4);
		printf("$%d", size);
		return;
		}

	case 'S':  /* structure assignment */
		{
			register int size;

			size = p->n_stsize;
			l = r = NULL; /* XXX gcc */
			if( p->n_op == STASG ){
				l = p->n_left;
				r = p->n_right;

				}
			else if( p->n_op == STARG ){
				/* store an arg into a temporary */
				printf("\tsubl2 $%d,%%sp\n",
				    size < 4 ? 4 : size);
				l = mklnode(OREG, 0, SP, INT);
				r = p->n_left;
				}
			else cerror( "STASG bad" );

			if( r->n_op == ICON ) r->n_op = NAME;
			else if( r->n_op == REG ) r->n_op = OREG;
			else if( r->n_op != OREG ) cerror( "STASG-r" );

		if (size != 0) {
			if( size <= 0 || size > 65535 )
				cerror("structure size <0=0 or >65535");

			switch(size) {
				case 1:
					printf("	movb	");
					break;
				case 2:
					printf("	movw	");
					break;
				case 4:
					printf("	movl	");
					break;
				case 8:
					printf("	movq	");
					break;
				default:
					printf("	movc3	$%d,", size);
					break;
			}
			adrput(stdout, r);
			printf(",");
			adrput(stdout, l);
			printf("\n");
		}

			if( r->n_op == NAME ) r->n_op = ICON;
			else if( r->n_op == OREG ) r->n_op = REG;
			if (p->n_op == STARG)
				tfree(l);

			}
		break;

	default:
		comperr("illegal zzzcode '%c'", c);
	}
}
示例#6
0
static void
sconv(NODE *p)
{
	NODE *l = p->n_left;
	TWORD ts, td;
	int o;

	/*
	 * Source node may be in register or memory.
	 * Result is always in register.
	 */
	ts = l->n_type;
	if (ISPTR(ts))
		ts = UNSIGNED;
	td = p->n_type;
	ts = ts < LONG ? ts-2 : ts-4;
	td = td < LONG ? td-2 : td-4;

	o = scary[ts][td];
	switch (o) {
	case MLE:
	case MLZ:
		expand(p, INAREG|INBREG, "\tmovl\tAL,A1\n");
		break;

	case MVD:
		if (l->n_op == REG && regno(l) == regno(getlr(p, '1')))
			break; /* unneccessary move */
		expand(p, INAREG|INBREG, "\tmovZR\tAL,A1\n");
		break;

	case CSE:
		expand(p, INAREG|INBREG, "\tcvtZLl\tAL,A1\n");
		break;

	case CVT:
		expand(p, INAREG|INBREG, "\tcvtZLZR\tAL,A1\n");
		break;

	case MZE:
		expand(p, INAREG|INBREG, "\tmovzZLl\tAL,A1\n");
		break;

	case MVZ:
		expand(p, INAREG|INBREG, "\tmovzZLZR\tAL,A1\n");
		break;

	case MZC:
		expand(p, INAREG|INBREG, "\tmovzZLl\tAL,A1\n");
		expand(p, INAREG|INBREG, "\tcvtlZR\tA1,A1\n");
		break;

	case 'I': /* unsigned to double */
		expand(p, INAREG|INBREG, "\tcvtld\tAL,A1\n");
		printf("\tjgeq\t1f\n");
		expand(p, INAREG|INBREG, "\taddd2\t$0d4.294967296e+9,A1\n");
		printf("1:\n");
		break;
	default:
		comperr("unsupported conversion %d", o);
	}
	switch (o) {
	case MLE:
	case CSE:
		expand(p, INBREG, "\tashl\t$-31,A1,U1\n");
		break;
	case MLZ:
	case MZE:
		expand(p, INAREG|INBREG, "\tclrl\tU1\n");
		break;
	}
}
示例#7
0
void
zzzcode(NODE *p, int c)
{
	struct attr *ap;
	NODE *l;
	int pr, lr;
	char *ch;
	char sv;

	switch (c) {
	case 'A': /* swap st0 and st1 if right is evaluated second */
		if ((p->n_su & DORIGHT) == 0) {
			if (logop(p->n_op))
				printf("	fxch\n");
			else
				printf("r");
		}
		break;

	case 'C':  /* remove from stack after subroutine call */
#ifdef notdef
		if (p->n_left->n_flags & FSTDCALL)
			break;
#endif
		pr = p->n_qual;
		if (attr_find(p->n_ap, ATTR_I86_FPPOP))
			printf("	fstp	st(0)\n");
		if (p->n_op == UCALL)
			return; /* XXX remove ZC from UCALL */
		if (pr) {
			if (pr == 2)
				printf("	inc sp\n	inc sp\n");
			else
				printf("	add sp,#%d\n", pr);
		}
		break;

	case 'D': /* Long comparision */
		twollcomp(p);
		break;

	case 'F': /* Structure argument */
		starg(p);
		break;

	case 'G': /* Floating point compare */
		fcomp(p);
		break;

	case 'H': /* assign of long between regs */
		rmove(DECRA(p->n_right->n_reg, 0),
		    DECRA(p->n_left->n_reg, 0), LONGLONG);
		break;

	case 'I': /* float casts */
		fcast(p);
		break;

	case 'J': /* convert unsigned long long to floating point */
		ulltofp(p);
		break;

	case 'K': /* Load long reg into another reg */
		rmove(regno(p), DECRA(p->n_reg, 0), LONGLONG);
		break;

	case 'M': /* Output sconv move, if needed */
		l = getlr(p, 'L');
		/* XXX fixneed: regnum */
		pr = DECRA(p->n_reg, 0);
		lr = DECRA(l->n_reg, 0);
		if ((pr == AL && lr == AX) || (pr == BL && lr == BX) ||
		    (pr == CL && lr == CX) || (pr == DL && lr == DX))
			;
		else
			printf("	mov %s, %cL\n",
			    rnames[pr], rnames[lr][1]);
		l->n_rval = l->n_reg = p->n_reg; /* XXX - not pretty */
		break;

	case 'N': /* output extended reg name */
		printf("%s", rnames[getlr(p, '1')->n_rval]);
		break;

	case 'O': /* print out emulated ops */
		pr = 8;
		sv = 'l';
#if 0		
		if (p->n_op == RS || p->n_op == LS) {
			llshft(p);
			break;
		}
#endif
		if (p->n_op != RS && p->n_op != LS) {
			/* For 64bit we will need to push pointers
			   not u64 */
			expand(p, INCREG, "\tpush UR\n\tpush AR\n");
			expand(p, INCREG, "\tpush UL\n\tpush AL\n");
		} else {
			/* AR is a BREG so this goes wrong.. need an AREG
			   but putting an AREG in the table rule makes the
			   compiler shit itself - FIXME */
			expand(p, INAREG, "\tpush AR\n");
			expand(p, INCREG, "\tpush UL\n\tpush AL\n");
			pr = 6;
		}
		
		if (p->n_type == LONGLONG || p->n_type == ULONGLONG)
			sv = 'L';
		if (p->n_op == DIV && (p->n_type == ULONG || p->n_type == ULONGLONG))
			ch = "udiv";
		else if (p->n_op == MUL && (p->n_type == ULONG || p->n_type == ULONGLONG))
			ch = "umul";
		else if (p->n_op == DIV) ch = "div";
		else if (p->n_op == MUL) ch = "mul";
		else if (p->n_op == MOD && (p->n_type == ULONG || p->n_type == ULONGLONG))
			ch = "umod";
		else if (p->n_op == MOD) ch = "mod";
		else if (p->n_op == LS) ch = "ls";
		else if (p->n_op == RS && (p->n_type == ULONG || p->n_type == ULONGLONG))
			ch = "rs";
		else if (p->n_op == RS) ch = "urs";
		else ch = 0, comperr("ZO");
		printf("\tcall " EXPREFIX "__%c%sdi3\n\tadd %s,#%d\n",
			sv, ch, rnames[SP], pr);
                break;
	
	case 'P': /* typeless right hand */
		suppress_type = 1;
		break;

	case 'Q': /* emit struct assign */
		/*
		 * Put out some combination of movs{b,w}
		 * si/di/cx are available.
		 * FIXME: review es: and direction flag implications
		 */
		expand(p, INAREG, "	lea al,di\n");
		ap = attr_find(p->n_ap, ATTR_P2STRUCT);
		if (ap->iarg(0) < 32) {
			int i = ap->iarg(0) >> 1;
			while (i) {
				expand(p, INAREG, "	movsw\n");
				i--;
			}
		} else {
示例#8
0
文件: match.c 项目: JamesLinus/pcc
/*
 * Find a UNARY op that satisfy the needs.
 * For now, the destination is always a register.
 * Both source and dest types must match, but only source (left)
 * shape is of interest.
 */
int
finduni(NODE *p, int cookie)
{
	extern int *qtable[];
	struct optab *q;
	NODE *l, *r;
	int i, shl = 0, num = 4;
	int *ixp, idx = 0;
	int sh;

	F2DEBUG(("finduni tree: %s\n", prcook(cookie)));
	F2WALK(p);

	l = getlr(p, 'L');
	if (p->n_op == CALL || p->n_op == FORTCALL || p->n_op == STCALL)
		r = p;
	else
		r = getlr(p, 'R');
	ixp = qtable[p->n_op];
	for (i = 0; ixp[i] >= 0; i++) {
		q = &table[ixp[i]];

		F2DEBUG(("finduni: ixp %d\n", ixp[i]));
		if (!acceptable(q))		/* target-dependent filter */
			continue;

		if (ttype(l->n_type, q->ltype) == 0)
			continue; /* Type must be correct */

		F2DEBUG(("finduni got left type\n"));
		if (ttype(r->n_type, q->rtype) == 0)
			continue; /* Type must be correct */

		F2DEBUG(("finduni got types\n"));
		if ((shl = chcheck(l, q->lshape, q->rewrite & RLEFT)) == SRNOPE)
			continue;

		F2DEBUG(("finduni got shapes %d\n", shl));

		if ((cookie & q->visit) == 0)	/* check correct return value */
			continue;		/* XXX - should check needs */

		/* avoid clobbering of longlived regs */
		/* let register allocator coalesce */
		if ((q->rewrite & RLEFT) && (shl == SRDIR) /* && isreg(l) */)
			shl = SRREG;

		F2DEBUG(("finduni got cookie\n"));
		if (q->needs & REWRITE)
			break;	/* Done here */

		if (shl >= num)
			continue;
		num = shl;
		idx = ixp[i];

		if (shl == SRDIR)
			break;
	}

	if (num == 4) {
		F2DEBUG(("finduni failed\n"));
	} else
		F2DEBUG(("finduni entry %d(%s)\n", idx, srtyp[num]));

	if (num == 4) {
		if (setuni(p, cookie))
			return FRETRY;
		return FFAIL;
	}
	q = &table[idx];

	sh = shswitch(-1, p->n_left, q->lshape, cookie,
	    q->rewrite & RLEFT, num);
	if (sh == -1)
		sh = ffs(cookie & q->visit & INREGS)-1;
	if (sh == -1)
		sh = 0;

	F2DEBUG(("finduni: node %p (%s)\n", p, prcook(1 << sh)));
	p->n_su = MKIDX(idx, 0);
	SCLASS(p->n_su, sh);
	return sh;
}
示例#9
0
文件: match.c 项目: JamesLinus/pcc
/*
 * Find a matching assign op.
 *
 * Level assignment for priority:
 *	left	right	prio
 *	-	-	-
 *	direct	direct	1
 *	direct	REG	2
 *	direct	OREG	3
 *	OREG	direct	4
 *	OREG	REG	5
 *	OREG	OREG	6
 */
int
findasg(NODE *p, int cookie)
{
	extern int *qtable[];
	struct optab *q;
	int i, sh, shl, shr, lvl = 10;
	NODE *l, *r;
	int *ixp;
	struct optab *qq = NULL; /* XXX gcc */
	int idx = 0, gol = 0, gor = 0;

	shl = shr = 0;

	F2DEBUG(("findasg tree: %s\n", prcook(cookie)));
	F2WALK(p);

	ixp = qtable[p->n_op];
	l = getlr(p, 'L');
	r = getlr(p, 'R');
	for (i = 0; ixp[i] >= 0; i++) {
		q = &table[ixp[i]];

		F2DEBUG(("findasg: ixp %d\n", ixp[i]));
		if (!acceptable(q))		/* target-dependent filter */
			continue;

		if (ttype(l->n_type, q->ltype) == 0 ||
		    ttype(r->n_type, q->rtype) == 0)
			continue; /* Types must be correct */

		if ((cookie & q->visit) == 0)
			continue; /* must get a result */

		F2DEBUG(("findasg got types\n"));
#ifdef mach_pdp11 /* XXX - check for other targets too */
		if (p->n_op == STASG && ISPTR(l->n_type)) {
			/* Accept lvalue to be in register */
			/* if struct assignment is given a pointer */
			if ((shl = chcheck(l, q->lshape,
			    q->rewrite & RLEFT)) == SRNOPE)
				continue;
		} else
#endif
		{
			if ((shl = tshape(l, q->lshape)) == SRNOPE)
				continue;
			if (shl == SRREG)
				continue;
		}

		F2DEBUG(("findasg lshape %d\n", shl));
		F2WALK(l);

		if ((shr = chcheck(r, q->rshape, q->rewrite & RRIGHT)) == SRNOPE)
			continue;

		F2DEBUG(("findasg rshape %d\n", shr));
		F2WALK(r);
		if (q->needs & REWRITE)
			break;	/* Done here */

		if (lvl <= (shl + shr))
			continue;

		lvl = shl + shr;
		qq = q;
		idx = ixp[i];
		gol = shl;
		gor = shr;
	}

	if (lvl == 10) {
		F2DEBUG(("findasg failed\n"));
		if (setasg(p, cookie))
			return FRETRY;
		return FFAIL;
	}
	F2DEBUG(("findasg entry %d(%s,%s)\n", idx, srtyp[gol], srtyp[gor]));

	sh = -1;
	sh = shswitch(sh, p->n_left, qq->lshape, cookie,
	    qq->rewrite & RLEFT, gol);

	sh = shswitch(sh, p->n_right, qq->rshape, cookie,
	    qq->rewrite & RRIGHT, gor);

#ifdef mach_pdp11 /* XXX all targets? */
	lvl = 0;
	if (cookie == FOREFF)
		lvl = RVEFF, sh = 0;
	else if (cookie == FORCC)
		lvl = RVCC, sh = 0;
	else if (sh == -1) {
		sh = ffs(cookie & qq->visit & INREGS)-1;
#ifdef PCC_DEBUG
		if (sh == -1)
			comperr("findasg bad shape");
#endif
		SCLASS(lvl,sh);
	} else
		SCLASS(lvl,sh);
	p->n_su = MKIDX(idx, lvl);
#else
	if (sh == -1) {
		if (cookie == FOREFF)
			sh = 0;
		else
			sh = ffs(cookie & qq->visit & INREGS)-1;
	}
	F2DEBUG(("findasg: node %p class %d\n", p, sh));

	p->n_su = MKIDX(idx, 0);
	SCLASS(p->n_su, sh);
#endif /* mach_pdp11 */
#ifdef FINDMOPS
	p->n_su &= ~ISMOPS;
#endif
	return sh;
}
示例#10
0
文件: match.c 项目: JamesLinus/pcc
/*
 * Find the best relation op for matching the two trees it has.
 * This is a sub-version of the function findops() above.
 * The instruction with the lowest grading is emitted.
 *
 * Level assignment for priority:
 *	left	right	prio
 *	-	-	-
 *	direct	direct	1
 *	direct	OREG	2	# make oreg
 *	OREG	direct	2	# make oreg
 *	OREG	OREG	2	# make both oreg
 *	direct	REG	3	# put in reg
 *	OREG	REG	3	# put in reg, make oreg
 *	REG	direct	3	# put in reg
 *	REG	OREG	3	# put in reg, make oreg
 *	REG	REG	4	# put both in reg
 */
int
relops(NODE *p)
{
	extern int *qtable[];
	struct optab *q;
	int i, shl = 0, shr = 0, sh;
	NODE *l, *r;
	int *ixp, idx = 0;
	int lvl = 10, gol = 0, gor = 0;

	F2DEBUG(("relops tree:\n"));
	F2WALK(p);

	l = getlr(p, 'L');
	r = getlr(p, 'R');
	ixp = qtable[p->n_op];
	for (i = 0; ixp[i] >= 0; i++) {
		q = &table[ixp[i]];

		F2DEBUG(("relops: ixp %d\n", ixp[i]));
		if (!acceptable(q))		/* target-dependent filter */
			continue;

		if (ttype(l->n_type, q->ltype) == 0 ||
		    ttype(r->n_type, q->rtype) == 0)
			continue; /* Types must be correct */

		F2DEBUG(("relops got types\n"));
		if ((shl = chcheck(l, q->lshape, 0)) == SRNOPE)
			continue;
		F2DEBUG(("relops lshape %d\n", shl));
		F2WALK(p);
		if ((shr = chcheck(r, q->rshape, 0)) == SRNOPE)
			continue;
		F2DEBUG(("relops rshape %d\n", shr));
		F2WALK(p);
		if (q->needs & REWRITE)
			break;	/* Done here */

		if (lvl <= (shl + shr))
			continue;
		lvl = shl + shr;
		idx = ixp[i];
		gol = shl;
		gor = shr;
	}
	if (lvl == 10) {
		F2DEBUG(("relops failed\n"));
		if (setbin(p))
			return FRETRY;
		return FFAIL;
	}
	F2DEBUG(("relops entry %d(%s %s)\n", idx, srtyp[gol], srtyp[gor]));

	q = &table[idx];

	(void)shswitch(-1, p->n_left, q->lshape, INREGS,
	    q->rewrite & RLEFT, gol);

	(void)shswitch(-1, p->n_right, q->rshape, INREGS,
	    q->rewrite & RRIGHT, gor);

	sh = 0;
	if (q->rewrite & RLEFT)
		sh = ffs(q->lshape & INREGS)-1;
	else if (q->rewrite & RRIGHT)
		sh = ffs(q->rshape & INREGS)-1;

	F2DEBUG(("relops: node %p\n", p));
	p->n_su = MKIDX(idx, 0);
	SCLASS(p->n_su, sh);
	return 0;
}
示例#11
0
文件: match.c 项目: JamesLinus/pcc
/*
 * Find the best instruction to evaluate the given tree.
 * Best is to match both subnodes directly, second-best is if
 * subnodes must be evaluated into OREGs, thereafter if nodes 
 * must be put into registers.
 * Whether 2-op instructions or 3-op is preferred is depending on in
 * which order they are found in the table.
 * mtchno is set to the count of regs needed for its legs.
 */
int
findops(NODE *p, int cookie)
{
	extern int *qtable[];
	struct optab *q, *qq = NULL;
	int i, shl, shr, *ixp, sh;
	int lvl = 10, idx = 0, gol = 0, gor = 0;
	NODE *l, *r;

	F2DEBUG(("findops node %p (%s)\n", p, prcook(cookie)));
	F2WALK(p);

	ixp = qtable[p->n_op];
	l = getlr(p, 'L');
	r = getlr(p, 'R');
	for (i = 0; ixp[i] >= 0; i++) {
		q = &table[ixp[i]];

		F2DEBUG(("findop: ixp %d str %s\n", ixp[i], q->cstring));
		if (!acceptable(q))		/* target-dependent filter */
			continue;

		if (ttype(l->n_type, q->ltype) == 0 ||
		    ttype(r->n_type, q->rtype) == 0)
			continue; /* Types must be correct */

		if ((cookie & q->visit) == 0)
			continue; /* must get a result */

		F2DEBUG(("findop got types\n"));

		if ((shl = chcheck(l, q->lshape, q->rewrite & RLEFT)) == SRNOPE)
			continue;

		F2DEBUG(("findop lshape %s\n", srtyp[shl]));
		F2WALK(l);

		if ((shr = chcheck(r, q->rshape, q->rewrite & RRIGHT)) == SRNOPE)
			continue;

		F2DEBUG(("findop rshape %s\n", srtyp[shr]));
		F2WALK(r);

		/* Help register assignment after SSA by preferring */
		/* 2-op insns instead of 3-ops */
		if (xssa && (q->rewrite & RLEFT) == 0 && shl == SRDIR)
			shl = SRREG;

		if (q->needs & REWRITE)
			break;  /* Done here */

		if (lvl <= (shl + shr))
			continue;
		lvl = shl + shr;
		qq = q;
		idx = ixp[i];
		gol = shl;
		gor = shr;
	}
	if (lvl == 10) {
		F2DEBUG(("findops failed\n"));
		if (setbin(p))
			return FRETRY;
		return FFAIL;
	}

	F2DEBUG(("findops entry %d(%s,%s)\n", idx, srtyp[gol], srtyp[gor]));

	sh = -1;

#ifdef mach_pdp11
	if (cookie == FORCC && p->n_op != AND)	/* XXX - fix */
		cookie = INREGS;
#else
	if (cookie == FORCC)
		cookie = INREGS;
#endif

	sh = shswitch(sh, p->n_left, qq->lshape, cookie,
	    qq->rewrite & RLEFT, gol);
	sh = shswitch(sh, p->n_right, qq->rshape, cookie,
	    qq->rewrite & RRIGHT, gor);

	if (sh == -1) {
		if (cookie == FOREFF || cookie == FORCC)
			sh = 0;
		else
			sh = ffs(cookie & qq->visit & INREGS)-1;
	}
	F2DEBUG(("findops: node %p sh %d (%s)\n", p, sh, prcook(1 << sh)));
	p->n_su = MKIDX(idx, 0);
	SCLASS(p->n_su, sh);
	return sh;
}
示例#12
0
文件: match.c 项目: JamesLinus/pcc
/*
 * generate code by interpreting table entry
 */
void
expand(NODE *p, int cookie, char *cp)
{
	CONSZ val;

#if 0
	printf("expand\n");
	fwalk(p, e2print, 0);
#endif

	for( ; *cp; ++cp ){
		switch( *cp ){

		default:
			putchar(*cp);
			continue;  /* this is the usual case... */

		case 'Z':  /* special machine dependent operations */
			zzzcode( p, *++cp );
			continue;

		case 'F':  /* this line deleted if FOREFF is active */
			if (cookie & FOREFF) {
				while (*cp && *cp != '\n')
					cp++;
				if (*cp == 0)
					return;
			}
			continue;

		case 'S':  /* field size */
			if (fldexpand(p, cookie, &cp))
				continue;
			printf("%d", FLDSZ(p->n_rval));
			continue;

		case 'H':  /* field shift */
			if (fldexpand(p, cookie, &cp))
				continue;
			printf("%d", FLDSHF(p->n_rval));
			continue;

		case 'M':  /* field mask */
		case 'N':  /* complement of field mask */
			if (fldexpand(p, cookie, &cp))
				continue;
			val = 1;
			val <<= FLDSZ(p->n_rval);
			--val;
			val <<= FLDSHF(p->n_rval);
			adrcon( *cp=='M' ? val : ~val );
			continue;

		case 'L':  /* output special label field */
			if (*++cp == 'C')
				printf(LABFMT, p->n_label);
			else
				printf(LABFMT, (int)getlval(getlr(p,*cp)));
			continue;

		case 'O':  /* opcode string */
#ifdef FINDMOPS
			if (p->n_op == ASSIGN)
				hopcode(*++cp, p->n_right->n_op);
			else
#endif
			hopcode( *++cp, p->n_op );
			continue;

		case 'B':  /* byte offset in word */
			val = getlval(getlr(p,*++cp));
			val = BYTEOFF(val);
			printf( CONFMT, val );
			continue;

		case 'C': /* for constant value only */
			conput(stdout, getlr( p, *++cp ) );
			continue;

		case 'I': /* in instruction */
			insput( getlr( p, *++cp ) );
			continue;

		case 'A': /* address of */
			adrput(stdout, getlr( p, *++cp ) );
			continue;

		case 'U': /* for upper half of address, only */
			upput(getlr(p, *++cp), SZLONG);
			continue;

			}

		}

	}
示例#13
0
文件: match.c 项目: JamesLinus/pcc
/*
 * Try to find constructs like "a = a + 1;" and match them together
 * with instructions like "incl a" or "addl $1,a".
 *
 * Level assignment for priority:
 *	left	right	prio
 *	-	-	-
 *	direct	direct	1
 *	direct	REG	2
 *	direct	OREG	3
 *	OREG	direct	4
 *	OREG	REG	5
 *	OREG	OREG	6
 */
int
findmops(NODE *p, int cookie)
{
	extern int *qtable[];
	struct optab *q;
	int i, sh, shl, shr, lvl = 10;
	NODE *l, *r;
	int *ixp;
	struct optab *qq = NULL; /* XXX gcc */
	int idx = 0, gol = 0, gor = 0;

	shl = shr = 0;

	F2DEBUG(("findmops tree: %s\n", prcook(cookie)));
	F2WALK(p);

	l = getlr(p, 'L');
	r = getlr(p, 'R');
	/* See if this is a usable tree to work with */
	/* Currently only check for leaves */
	if (optype(r->n_op) != BITYPE || treecmp(l, r->n_left) == 0)
		return FFAIL;

	F2DEBUG(("findmops is useable\n"));

	/* We can try to find a match.  Use right op */
	ixp = qtable[r->n_op];
	l = getlr(r, 'L');
	r = getlr(r, 'R');

	for (i = 0; ixp[i] >= 0; i++) {
		q = &table[ixp[i]];

		F2DEBUG(("findmops: ixp %d\n", ixp[i]));
		if (!acceptable(q))		/* target-dependent filter */
			continue;

		if (ttype(l->n_type, q->ltype) == 0 ||
		    ttype(r->n_type, q->rtype) == 0)
			continue; /* Types must be correct */

		F2DEBUG(("findmops got types\n"));

		switch (cookie) {
		case FOREFF:
			if ((q->visit & FOREFF) == 0)
				continue; /* Not only for side effects */
			break;
		case FORCC:
			if ((q->visit & FORCC) == 0)
				continue; /* Not only for side effects */
			break;
		default:
			if ((cookie & q->visit) == 0)
				continue; /* Won't match requested shape */
			if (((cookie & INREGS & q->lshape) == 0) || !isreg(l))
				continue; /* Bad return register */
			break;
		}
		F2DEBUG(("findmops cookie\n"));

		/*
		 * left shape must match left node.
		 */
		if ((shl = tshape(l, q->lshape)) != SRDIR && (shl != SROREG))
			continue;

		F2DEBUG(("findmops lshape %s\n", srtyp[shl]));
		F2WALK(l);

		if ((shr = chcheck(r, q->rshape, 0)) == SRNOPE)
			continue;

		F2DEBUG(("findmops rshape %s\n", srtyp[shr]));

		/*
		 * Only allow RLEFT. XXX
		 */
		if ((q->rewrite & (RLEFT|RRIGHT)) != RLEFT)
			continue;

		F2DEBUG(("rewrite OK\n"));

		F2WALK(r);
		if (q->needs & REWRITE)
			break;	/* Done here */

		if (lvl <= (shl + shr))
			continue;

		lvl = shl + shr;
		qq = q;
		idx = ixp[i];
		gol = shl;
		gor = shr;
	}

	if (lvl == 10)
		return FFAIL;
	F2DEBUG(("findmops entry %d(%s,%s)\n", idx, srtyp[gol], srtyp[gor]));

	/*
	 * Now we're here and have a match. left is semi-direct and 
	 * right may be anything.
	 */

	sh = -1;
	sh = shswitch(sh, p->n_left, qq->lshape, cookie,
	    qq->rewrite & RLEFT, gol);
	sh = shswitch(sh, r, qq->rshape, cookie, 0, gor);

	if (sh == -1) {
		if (cookie & (FOREFF|FORCC))
			sh = 0;
		else
			sh = ffs(cookie & qq->visit & INREGS)-1;
	}
	F2DEBUG(("findmops done: node %p class %d\n", p, sh));

	/* Trickery:  Set table index on assign to op instead */
	/* gencode() will remove useless nodes */
	p->n_su = MKIDX(idx, 0);
	p->n_su |= ISMOPS; /* XXX tell gencode to reduce the right tree */
	SCLASS(p->n_su, sh);

	return sh;
}
示例#14
0
文件: libero.c 项目: enadam/arf
/* Add $ptr to the records.  Called in mallfuncs context. */
static void *garbage(void *ptr, size_t size, int intracall)
{
   struct ero_st *mem;
   unsigned i, top, bottom;

   if (!ptr)
      /* malloc() failed, don't record. */
      return NULL;

   /* Update the counters whether we can make a record or not. */
   NAllocations++;
   Allocated += size;
   if (Peak < Allocated)
      Peak = Allocated;

   /* We are permitted to clobber errno because our caller
    * is going to return with success. */
   if (!Ero_pool && !(Ero_pool = new_ero_pool()))
      return ptr;

   mem = Ero_pool;
   Ero_pool = Ero_pool->next;
   mem->next = Memories;
   Memories = mem;
   NMemories++;

   mem->ptr = ptr;
   mem->size = size;
   mem->karma = 0;
   IF_THREAD_SAFE(mem->tid = gettid());

   mem->backtrace = NULL;
   if (!Backtrace_depth)
      goto skip_backtrace;
   if (!Backtraces && !(Backtraces = new_backtraces()))
      goto skip_backtrace;
   mem->backtrace = Backtraces;

   /* We're called through fun() -> malloc() -> garbage(),
    * ignore the top two frames.  The bottom two frames
    * are below main(), ignore them too. */
   top = 2;
   if (intracall)
      /* An accountant function called another hook, ignore that too. */
      top++;

#ifndef CONFIG_FAST_UNWIND
   /* Try getting the backtrace until $addrs is large enough.
    * Start with a large buffer to get away with as few retries
    * as possible. */
   bottom = 2;
   for (i = Backtrace_depth > 0 ? top+Backtrace_depth : 100; ; i += 100)
   {
      unsigned depth;
      void *addrs[i];
      struct backtrace_st *next;

      if ((depth = backtrace(addrs, i)) >= i && Backtrace_depth < 0)
         /* $addrs was too small. */
         continue;

      if (depth > top)
      {  /* Ignore $top frames. */
         depth -= top;
         if (top+depth < i && depth > bottom)
            /* If we got the full backtrace also ignore
             * the $bottom frames. */
            depth -= bottom;
      } else /* Don't ignore anyhing. */
         top = 0;

      /* Add the backtrace to $mem.  If #depth is larger than the CAPACITY
       * of backtrace_st chain up more. */
      for (;;)
      {
         int more;
         unsigned n;

         n = CAPACITY(Backtraces->addrs);
         more = n < depth;
         if (n > depth)
            n = depth;

         memcpy(Backtraces->addrs, &addrs[top], sizeof(addrs[0]) * n);
         if (!more)
         {
            /* NULL-pad the unused $addrs, so compare_backtraces() won't
             * tell apart identical backtraces because of garbage. */
            memset(&Backtraces->addrs[n], 0,
               sizeof(Backtraces->addrs[0]) * (CAPACITY(Backtraces->addrs)-n));
            break;
         }

         if (!Backtraces->next && !(Backtraces->next = new_backtraces()))
            /* The bottom of the backtrace will be lost. */
            break;
         Backtraces = Backtraces->next;
         top   += n;
         depth -= n;
      } /* for */
      next = Backtraces->next;
      Backtraces->next = NULL;
      Backtraces = next;

      break;
   } /* for */
#else /* CONFIG_FAST_UNWIND */
   /* We need to be able to store at least $top addresses.
    * If not, ignoring top/bottom frames may break. */
   ASSERT(CAPACITY(Backtraces->addrs) >= 3);

   /* arf leaves less junk at the bottom than backtrace(). */
   bottom = 1;

   do
   {
      unsigned depth;
      void const *sseg;
		void const *const *fp, *lr;
      struct backtrace_st *prev, *next;

      /* We don't know beforehand the depth of the backtrace,
       * so store the addresses in $Backtraces as we unwind
       * the stack iteratively. */
      prev = NULL;
      sseg = NULL;
		fp = __builtin_frame_address(0);
		for (i = depth = 0; ; i++, depth++)
		{
         if (!(fp = getlr(fp, &lr, &sseg))
            || (Backtrace_depth > 0 && depth >= Backtrace_depth))
         {  /* End of backtrace, ignore the bottom frames if we can. */
            if (!fp && !top && depth > bottom)
            {
               if (i <= bottom)
               {  /* The addresses in $Backtraces are all ignored,
                   * discard the whole page. */
                  Backtraces = prev;
                  i += CAPACITY(Backtraces->addrs) - bottom;
               } else
                  i -= bottom;
            }

            /* Zero out the unused slots (which can be 0). */
            memset(&Backtraces->addrs[i], 0,
               sizeof(Backtraces->addrs[0])
                  * (CAPACITY(Backtraces->addrs)-i));
            break;
         }

         if (depth == top)
            /* Time to ignore $top. */
            i = depth = top = 0;
         else if (i >= CAPACITY(Backtraces->addrs))
         {  /* $Backtraces is full, get a new page. */
            if (!Backtraces->next && !(Backtraces->next = new_backtraces()))
               break;
            prev = Backtraces;
            Backtraces = Backtraces->next;
            i = 0;
         }

         Backtraces->addrs[i] = lr;
		} /* for */

      /* NULL-terminate $mem->backtaces and dequeue the tail
       * from $Backtraces. */
      next = Backtraces->next;
      Backtraces->next = NULL;
      Backtraces = next;
   } while (0);
#endif /* CONFIG_FAST_UNWIND */

skip_backtrace:
   return ptr;
} /* garbage */