+/*
+ * Generate code for storage conversions.
+ */
+sconv(p, forcc)
+ NODE *p;
+{
+ register NODE *l, *r;
+ register wfrom, wto;
+ int oltype;
+
+ l = getlr(p, '1');
+ oltype = l->in.type, l->in.type = r->in.type;
+ r = getlr(p, 'L');
+ wfrom = tlen(r), wto = tlen(l);
+ if (wfrom == wto) /* e.g. int -> unsigned */
+ goto done;
+ /*
+ * Conversion in registers requires care
+ * as cvt and movz instruction don't work
+ * as expected (they end up as plain mov's).
+ */
+ if (l->in.op == REG && r->in.op == REG) {
+ if (ISUNSIGNED(r->in.type)) { /* unsigned, mask */
+ if (r->tn.lval != l->tn.lval) {
+ printf("\tandl3\t$%d,", (1<<(wto*SZCHAR))-1);
+ adrput(r);
+ putchar(',');
+ } else
+ printf("\tandl2\t$%d,", (1<<(wto*SZCHAR))-1);
+ adrput(l);
+ } else { /* effect sign-extend */
+ int shift = (sizeof (int)-wto)*SZCHAR;
+ printf("\tshll\t$%d,", shift);
+ adrput(r); putchar(','); adrput(l);
+ printf("\n\tshar\t$%d,", shift);
+ adrput(l); putchar(','); adrput(l);
+ if (wfrom != sizeof (int)) {
+ /*
+ * Must mask if result is shorter than
+ * the width of a register (to account
+ * for register treatment).
+ */
+ printf("\n\tandl2\t$%d,",(1<<(wfrom*SZCHAR))-1);
+ adrput(l);
+ } else
+ forcc = 0;
+ }
+ /*
+ * If condition codes are required and the last thing
+ * we did was mask the result, then we must generate a
+ * test of the appropriate type.
+ */
+ if (forcc) {
+ printf("\n\tcmp");
+ prtype(l);
+ putchar('\t');
+ printf("$0,");
+ adrput(l);
+ }
+ } else {
+ /*
+ * Conversion with at least one parameter in memory.
+ */
+ if (wfrom < wto) { /* expanding datum */
+ if (ISUNSIGNED(r->in.type)) {
+ printf("\tmovz");
+ prtype(r);
+ /*
+ * If target is a register, generate
+ * movz?l so optimizer can compress
+ * argument pushes.
+ */
+ if (l->in.op == REG)
+ putchar('l');
+ else
+ prtype(l);
+ } else {
+ printf("\tcvt");
+ prtype(r), prtype(l);
+ }
+ putchar('\t');
+ adrput(r);
+ } else { /* shrinking dataum */
+ int off = wfrom - wto;
+ if (l->in.op == REG) {
+ printf("\tmovz");
+ prtype(l);
+ putchar('l');
+ } else {
+ printf("\tcvt");
+ prtype(l), prtype(r);
+ }
+ putchar('\t');
+ switch (r->in.op) {
+ case NAME: case OREG:
+ r->tn.lval += off;
+ adrput(r);
+ r->tn.lval -= off;
+ break;
+ case REG: case ICON: case UNARY MUL:
+ adrput(r);
+ break;
+ default:
+ cerror("sconv: bad shrink op");
+ /*NOTREACHED*/
+ }
+ }
+ putchar(',');
+ adrput(l);
+ }
+ putchar('\n');
+done:
+ l->in.type = oltype;
+}
+