in registers we use the stack code because shifts are too slow. We are
less stupid about constants. We get register source operand lengths right.
We distinguish between mova[bwl] in memory to register shrinking
conversions so that side effects are handled correctly.
SCCS-vsn: old/pcc/ccom.tahoe/local2.c 1.13
-static char sccsid[] = "@(#)local2.c 1.12 (Berkeley) %G%";
+static char sccsid[] = "@(#)local2.c 1.13 (Berkeley) %G%";
#endif
# include "pass2.h"
#endif
# include "pass2.h"
+/*
+ * Prlen() is a cheap prtype()...
+ */
+static char convtab[SZINT/SZCHAR + 1] = {
+ '?', 'b', 'w', '?', 'l'
+};
+#define prlen(len) putchar(convtab[len])
+
+
/*
* Generate code for integral scalar conversions.
/*
* Generate code for integral scalar conversions.
- * Many work-arounds for brain-damaged Tahoe register behavior.
+ * Some of this code is designed to work around a tahoe misfeature
+ * that causes sign- and zero- extension to be defeated in
+ * certain circumstances.
+ * Basically if the source operand of a CVT or MOVZ instruction is
+ * shorter than the destination, and the source is a register
+ * or an immediate constant, sign- and zero- extension are
+ * ignored and the high bits of the source are copied. (Note
+ * that zero-extension is not a problem for immediate
+ * constants.)
*/
sconv(p, forcc)
NODE *p;
*/
sconv(p, forcc)
NODE *p;
- srclen = tlen(src);
- srctype = src->in.op == REG ?
- ISUNSIGNED(src->in.type) ? UNSIGNED : INT :
- src->in.type;
+ if (src->in.op == REG) {
+ srclen = SZINT/SZCHAR;
+ srctype = ISUNSIGNED(src->in.type) ? UNSIGNED : INT;
+ } else {
+ srclen = tlen(src);
+ srctype = src->in.type;
+ }
+
+ if (src->in.op == ICON) {
+ if (src->tn.lval == 0) {
+ putstr("clr");
+ prtype(dst);
+ putchar('\t');
+ adrput(dst);
+ return;
+ }
+ if (dstlen < srclen) {
+ switch (dsttype) {
+ case CHAR:
+ src->tn.lval = (char) src->tn.lval;
+ break;
+ case UCHAR:
+ src->tn.lval = (unsigned char) src->tn.lval;
+ break;
+ case SHORT:
+ src->tn.lval = (short) src->tn.lval;
+ break;
+ case USHORT:
+ src->tn.lval = (unsigned short) src->tn.lval;
+ break;
+ }
+ }
+ if (dst->in.op == REG) {
+ dsttype = INT;
+ dstlen = SZINT/SZCHAR;
+ }
+ srctype = dsttype;
+ srclen = dstlen;
+ }
if (srclen < dstlen) {
if (srctype == CHAR && dsttype == USHORT && dst->in.op == REG) {
if (srclen < dstlen) {
if (srctype == CHAR && dsttype == USHORT && dst->in.op == REG) {
}
if (srclen > dstlen && dst->in.op == REG) {
}
if (srclen > dstlen && dst->in.op == REG) {
+ /* if dst is a register, the result must look like an int */
if (src->in.op == REG) {
if (ISUNSIGNED(dsttype)) {
val = (1 << dstlen * SZCHAR) - 1;
if (src->in.op == REG) {
if (ISUNSIGNED(dsttype)) {
val = (1 << dstlen * SZCHAR) - 1;
- val = SZINT - srclen * SZCHAR;
- printf("shll\t$%d,", val);
+ /*
+ * Sign extension in register can also be
+ * accomplished by shifts, but unfortunately
+ * shifts are extremely slow, due to the lack
+ * of a barrel shifter.
+ */
+ putstr("pushl\t");
- putchar(',');
- adrput(dst);
- printf("\n\tshar\t$%d,", val);
- adrput(dst);
- putchar(',');
+ putstr("\n\tcvt");
+ prlen(dstlen);
+ printf("l\t%d(sp),", SZINT/SZCHAR - dstlen);
+ putstr("\n\tmovab\t4(sp),sp");
+ if (forcc) {
+ /* inverted test */
+ putstr("\n\tcmpl\t$0,");
+ adrput(dst);
+ }
return;
}
tmp = talloc();
return;
}
tmp = talloc();
} else {
/* we must store src's address */
*tmp = *dst;
} else {
/* we must store src's address */
*tmp = *dst;
+ putstr("mova");
+ prlen(srclen);
+ putchar('\t');
adrput(src);
putchar(',');
adrput(tmp);
adrput(src);
putchar(',');
adrput(tmp);
}
genconv(usrc, srclen, dstlen, src, dst)
}
genconv(usrc, srclen, dstlen, src, dst)
- int usrc, srclen, dstlen;
+ int usrc;
+ register int srclen, dstlen;
- static char convtab[SZINT/SZCHAR + 1] = {
- '?', 'b', 'w', '?', 'l'
- };
-
if (srclen != dstlen) {
if (usrc && srclen < dstlen)
putstr("movz");
else
putstr("cvt");
if (srclen != dstlen) {
if (usrc && srclen < dstlen)
putstr("movz");
else
putstr("cvt");
- putchar(convtab[srclen]);
- putchar(convtab[dstlen]);
putchar('\t');
adrput(src);
putchar(',');
putchar('\t');
adrput(src);
putchar(',');