+ if (srclen < dstlen) {
+ if (srctype == CHAR && dsttype == USHORT && dst->in.op == REG) {
+ /* (unsigned short) c; => sign extend to 16 bits */
+ putstr("cvtbl\t");
+ adrput(src);
+ putstr(",-(sp)\n\tmovzwl\t2(sp),");
+ adrput(dst);
+ putstr("\n\tmovab\t4(sp),sp");
+ if (forcc) {
+ putstr("\n\ttstl\t");
+ adrput(dst);
+ }
+ return;
+ }
+ genconv(ISUNSIGNED(srctype),
+ srclen, dst->in.op == REG ? SZINT/SZCHAR : dstlen,
+ src, dst, forcc);
+ return;
+ }
+
+ 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->tn.rval == dst->tn.rval)
+ /* conversion in place */
+ printf("andl2\t$%ld,", val);
+ else {
+ printf("andl3\t$%ld,", val);
+ adrput(src);
+ putchar(',');
+ }
+ adrput(dst);
+ return;
+ }
+ /*
+ * 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");
+ adrput(src);
+ putstr("\n\tcvt");
+ prlen(dstlen);
+ printf("l\t%d(sp),", SZINT/SZCHAR - dstlen);
+ adrput(dst);
+ putstr("\n\tmovab\t4(sp),sp");
+ if (forcc) {
+ putstr("\n\ttstl\t");
+ adrput(dst);
+ }
+ return;
+ }
+ tmp = talloc();
+ if ((src->in.op == NAME) ||
+ (src->in.op == UNARY MUL && src->in.left->in.op == ICON) ||
+ (src->in.op == OREG && !R2TEST(src->tn.rval))) {
+ /* we can increment src's address & pun it */
+ *tmp = *src;
+ tmp->tn.lval += srclen - dstlen;
+ } else {
+ /* we must store src's address */
+ *tmp = *dst;
+ putstr("mova");
+ prlen(srclen);
+ putchar('\t');
+ adrput(src);
+ putchar(',');
+ adrput(tmp);
+ putstr("\n\t");
+ tmp->tn.op = OREG;
+ tmp->tn.lval = srclen - dstlen;
+ }
+ genconv(ISUNSIGNED(dsttype), dstlen, SZINT/SZCHAR, tmp, dst, forcc);
+ tmp->in.op = FREE;
+ return;
+ }
+
+ genconv(neg ? -1 : ISUNSIGNED(dsttype),
+ srclen, dst->in.op == REG ? SZINT/SZCHAR : dstlen,
+ src, dst, forcc);
+}
+
+genconv(srcflag, srclen, dstlen, src, dst, forcc)
+ int srcflag;
+ register int srclen, dstlen;
+ NODE *src, *dst;
+ int forcc;
+{
+ if (srclen != dstlen) {
+ if (srcflag > 0 && srclen < dstlen)
+ putstr("movz");
+ else
+ putstr("cvt");
+ prlen(srclen);
+ } else if (srcflag < 0)
+ putstr("mneg");
+ else
+ putstr("mov");
+ prlen(dstlen);
+ putchar('\t');
+ adrput(src);
+ putchar(',');
+ adrput(dst);
+
+ /*
+ * This hack is made necessary by architecture problems
+ * described above
+ */
+ if (forcc && src->in.op == REG && srclen > dstlen) {
+ putstr("\n\ttst");
+ prlen(dstlen);
+ putchar('\t');
+ adrput(dst);