text: /*	Id: local2.c,v 1.106 2015/01/04 19:17:23 ragge Exp 	*/	
  /*	$NetBSD: local2.c,v 1.1.1.5 2016/02/09 20:28:26 plunky Exp $	*/
  /*
   * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in the
   *    documentation and/or other materials provided with the distribution.
   * 3. The name of the author may not be used to endorse or promote products
   *    derived from this software without specific prior written permission
   *
   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   */
  
  
  # include "pass2.h"
  # include <ctype.h>
  
  void acon(FILE *, NODE *p);
  int argsize(NODE *p);
  void genargs(NODE *p);
  
  static int offlab;
  int offarg;
  static int addto;
  static int regoff[16];
  
  void
  deflab(int label)
  {
  	printf(LABFMT ":\n", label);
  }
  
  void
  prologue(struct interpass_prolog *ipp)
  {
  	int i, j;
  
  	if (ipp->ipp_vis)
  		printf("	.globl %s\n", ipp->ipp_name);
  	printf("%s:\n", ipp->ipp_name);
  	addto = p2maxautooff;
  	if (addto >= AUTOINIT/SZCHAR)
  		addto -= AUTOINIT/SZCHAR;
  	addto /= SZINT/SZCHAR;	/* use words here */
  	printf("	push %s,%s\n",rnames[STKREG], rnames[FPREG]);
  	printf("	move %s,%s\n", rnames[FPREG],rnames[STKREG]);
  
  	for (i = ipp->ipp_regs[0], j = 0; i ; i >>= 1, j++) {
  		if (i & 1)
  			regoff[j] = addto++;
  	}
  	if (addto)
  		printf("	addi %s,0%o\n", rnames[STKREG], addto);
  
  	for (i = ipp->ipp_regs[0], j = 0; i ; i >>= 1, j++) {
  		if (i & 1)
  			printf("	movem %s,%d(%s)\n",
  			    rnames[j], regoff[j], rnames[STKREG]);
  	}
  }
  
  void
  eoftn(struct interpass_prolog *ipp)
  {
  	int i, j;
  
  	if (ipp->ipp_ip.ip_lbl == 0)
  		return; /* no code needs to be generated */
  	for (i = ipp->ipp_regs[0], j = 0; i ; i >>= 1, j++) {
  		if (i & 1)
  			printf("	move %s,%d(%s)\n",
  			    rnames[j], regoff[j], rnames[STKREG]);
  	}
  	printf("	move %s,%s\n", rnames[STKREG], rnames[FPREG]);
  	printf("	pop %s,%s\n", rnames[STKREG], rnames[FPREG]);
  	printf("	popj %s,\n", rnames[STKREG]);
  }
  
  #if 0
  void
  prologue(int regs, int autos)
  {
  	int i, addto;
  
  	offlab = getlab2();
  	if (regs < 0 || autos < 0) {
  		/*
  		 * non-optimized code, jump to epilogue for code generation.
  		 */
  		ftlab1 = getlab2();
  		ftlab2 = getlab2();
  		printf("	jrst L%d\n", ftlab1);
  		printf("L%d:\n", ftlab2);
  	} else {
  		/*
  		 * We here know what register to save and how much to 
  		 * add to the stack.
  		 */
  		autos = autos + (SZINT-1);
  		addto = (autos - AUTOINIT)/SZINT + (MAXRVAR-regs);
  		if (addto || gflag) {
  			printf("	push %s,%s\n",rnames[017], rnames[016]);
  			printf("	move %s,%s\n", rnames[016],rnames[017]);
  			for (i = regs; i < MAXRVAR; i++) {
  				int db = ((i+1) < MAXRVAR);
  				printf("	%smovem %s,0%o(%s)\n",
  				    db ? "d" : "",
  				    rnames[i+1], i+1-regs, rnames[016]);
  				if (db)
  					i++;
  			}
  			if (addto)
  				printf("	addi %s,0%o\n", rnames[017], addto);
  		} else
  			offarg = 1;
  	}
  }
  
  /*
   * End of block.
   */
  void
  eoftn(int regs, int autos, int retlab)
  {
  	register OFFSZ spoff;	/* offset from stack pointer */
  	int i;
  
  	spoff = autos + (SZINT-1);
  	if (spoff >= AUTOINIT)
  		spoff -= AUTOINIT;
  	spoff /= SZINT;
  	/* return from function code */
  	printf("L%d:\n", retlab);
  	if (gflag || isoptim == 0 || autos != AUTOINIT || regs != MAXRVAR) {
  		for (i = regs; i < MAXRVAR; i++) {
  			int db = ((i+1) < MAXRVAR);
  			printf("	%smove %s,0%o(%s)\n", db ? "d" : "",
  			    rnames[i+1], i+1-regs, rnames[016]);
  			if (db)
  				i++;
  		}
  		printf("	move %s,%s\n", rnames[017], rnames[016]);
  		printf("	pop %s,%s\n", rnames[017], rnames[016]);
  	}
  	printf("	popj %s,\n", rnames[017]);
  
  	/* Prolog code */
  	if (isoptim == 0) {
  		printf("L%d:\n", ftlab1);
  		printf("	push %s,%s\n", rnames[017], rnames[016]);
  		printf("	move %s,%s\n", rnames[016], rnames[017]);
  		for (i = regs; i < MAXRVAR; i++) {
  			int db = ((i+1) < MAXRVAR);
  			printf("	%smovem %s,0%o(%s)\n", db ? "d" : "",
  			    rnames[i+1], i+1-regs, rnames[016]);
  			spoff++;
  			if (db)
  				i++, spoff++;
  		}
  		if (spoff)
  			printf("	addi %s,0%llo\n", rnames[017], spoff);
  		printf("	jrst L%d\n", ftlab2);
  	}
  	printf("	.set " LABFMT ",0%o\n", offlab, MAXRVAR-regs);
  	offarg = isoptim = 0;
  }
  #endif
  
  /*
   * add/sub/...
   *
   * Param given:
   *	R - Register
   *	M - Memory
   *	C - Constant
   */
  void
  hopcode(int f, int o)
  {
  	cerror("hopcode: f %d %d", f, o);
  }
  
  char *
  rnames[] = {  /* keyed to register number tokens */
  	"%0", "%1", "%2", "%3", "%4", "%5", "%6", "%7",
  	"%10", "%11", "%12", "%13", "%14", "%15", "%16", "%17",
  	"%0", "%1", "%2", "%3", "%4", "%5", "%6", "%7",
  	"%10", "%11", "%12", "%13", "%14", "%15",
  };
  
  int
  tlen(p) NODE *p;
  {
  	switch(p->n_type) {
  		case CHAR:
  		case UCHAR:
  			return(1);
  
  		case SHORT:
  		case USHORT:
  			return(SZSHORT/SZCHAR);
  
  		case DOUBLE:
  			return(SZDOUBLE/SZCHAR);
  
  		case INT:
  		case UNSIGNED:
  		case LONG:
  		case ULONG:
  			return(SZINT/SZCHAR);
  
  		case LONGLONG:
  		case ULONGLONG:
  			return SZLONGLONG/SZCHAR;
  
  		default:
  			if (!ISPTR(p->n_type))
  				cerror("tlen type %d not pointer");
  			return SZPOINT(0)/SZCHAR;
  		}
  }
  
  static char *
  binskip[] = {
  	"e",	/* jumpe */
  	"n",	/* jumpn */
  	"le",	/* jumple */
  	"l",	/* jumpl */
  	"ge",	/* jumpge */
  	"g",	/* jumpg */
  };
  
  /*
   * Extract the higher 36 bits from a longlong.
   */
  static CONSZ
  gethval(CONSZ lval)
  {
  	CONSZ hval = (lval >> 35) & 03777777777LL;
  
  	if ((hval & 03000000000LL) == 03000000000LL) {
  		hval |= 0777000000000LL;
  	} else if ((hval & 03000000000LL) == 02000000000LL) {
  		hval &= 01777777777LL;
  		hval |= 0400000000000LL;
  	}
  	return hval;
  }
  
  /*
   * Do a binary comparision, and jump accordingly.
   */
  static void
  twocomp(NODE *p)
  {
  	int o = p->n_op;
  	extern int negrel[];
  	int isscon = 0, iscon = p->n_right->n_op == ICON;
  
  	if (o < EQ || o > GT)
  		cerror("bad binary conditional branch: %s", opst[o]);
  
  	if (iscon && p->n_right->n_name[0] != 0) {
  		printf("	cam%s ", binskip[negrel[o-EQ]-EQ]);
  		adrput(stdout, getlr(p, 'L'));
  		putchar(',');
  		printf("[ .long ");
  		adrput(stdout, getlr(p, 'R'));
  		putchar(']');
  		printf("\n	jrst L%d\n", p->n_label);
  		return;
  	}
  	if (iscon)
  		isscon = p->n_right->n_lval >= 0 &&
  		    p->n_right->n_lval < 01000000;
  
  	printf("	ca%c%s ", iscon && isscon ? 'i' : 'm',
  	    binskip[negrel[o-EQ]-EQ]);
  	adrput(stdout, getlr(p, 'L'));
  	putchar(',');
  	if (iscon && (isscon == 0)) {
  		printf("[ .long ");
  		adrput(stdout, getlr(p, 'R'));
  		putchar(']');
  	} else
  		adrput(stdout, getlr(p, 'R'));
  	printf("\n	jrst L%d\n", p->n_label);
  }
  
  /*
   * Compare byte/word pointers.
   * XXX - do not work for highest bit set in address
   */
  static void
  ptrcomp(NODE *p)
  {
  	printf("	rot "); adrput(stdout, getlr(p, 'L')); printf(",6\n");
  	printf("	rot "); adrput(stdout, getlr(p, 'R')); printf(",6\n");
  	twocomp(p);
  }
  
  /*
   * Do a binary comparision of two long long, and jump accordingly.
   * XXX - can optimize for constants.
   */
  static void     
  twollcomp(NODE *p)
  {       
  	int o = p->n_op;
  	int iscon = p->n_right->n_op == ICON;
  	int m = 0; /* XXX gcc */
  
  	if (o < EQ || o > GT)
  		cerror("bad long long conditional branch: %s", opst[o]);
  
  	/* Special strategy for equal/not equal */
  	if (o == EQ || o == NE) {
  		if (o == EQ)
  			m = getlab2();
  		printf("	came ");
  		upput(getlr(p, 'L'), SZLONG);
  		putchar(',');
  		if (iscon)
  			printf("[ .long ");
  		upput(getlr(p, 'R'), SZLONG);
  		if (iscon)
  			putchar(']');
  		printf("\n	jrst L%d\n", o == EQ ? m : p->n_label);
  		printf("	cam%c ", o == EQ ? 'n' : 'e');
  		adrput(stdout, getlr(p, 'L'));
  		putchar(',');
  		if (iscon)
  			printf("[ .long ");
  		adrput(stdout, getlr(p, 'R'));
  		if (iscon)
  			putchar(']');
  		printf("\n	jrst L%d\n", p->n_label);
  		if (o == EQ)
  			printf("L%d:\n", m);
  		return;
  	}
  	/* First test highword */
  	printf("	cam%ce ", o == GT || o == GE ? 'l' : 'g');
  	adrput(stdout, getlr(p, 'L'));
  	putchar(',');
  	if (iscon)
  		printf("[ .long ");
  	adrput(stdout, getlr(p, 'R'));
  	if (iscon)
  		putchar(']');
  	printf("\n	jrst L%d\n", p->n_label);
  
  	/* Test equality */
  	printf("	came ");
  	adrput(stdout, getlr(p, 'L'));
  	putchar(',');
  	if (iscon)
  		printf("[ .long ");
  	adrput(stdout, getlr(p, 'R'));
  	if (iscon)
  		putchar(']');
  	printf("\n	jrst L%d\n", m = getlab2());
  
  	/* Test lowword. Only works with pdp10 format for longlongs */
  	printf("	cam%c%c ", o == GT || o == GE ? 'l' : 'g',
  	    o == LT || o == GT ? 'e' : ' ');
  	upput(getlr(p, 'L'), SZLONG);
  	putchar(',');
  	if (iscon)  
  		printf("[ .long ");
  	upput(getlr(p, 'R'), SZLONG);
  	if (iscon)
  		putchar(']');
  	printf("\n	jrst L%d\n", p->n_label);
  	printf("L%d:\n", m);
  }
  
  /*
   * Print the correct instruction for constants.
   */
  static void
  constput(NODE *p)
  {
  	CONSZ val = p->n_right->n_lval;
  	int reg = p->n_left->n_rval;
  
  	/* Only numeric constant */
  	if (p->n_right->n_name[0] == '\0') {
  		if (val == 0) {
  			printf("movei %s,0", rnames[reg]);
  		} else if ((val & 0777777000000LL) == 0) {
  			printf("movei %s,0%llo", rnames[reg], val);
  		} else if ((val & 0777777) == 0) {
  			printf("hrlzi %s,0%llo", rnames[reg], val >> 18);
  		} else {
  			printf("move %s,[ .long 0%llo]", rnames[reg],
  			    szty(p->n_right->n_type) > 1 ? val :
  			    val & 0777777777777LL);
  		}
  		/* Can have more tests here, hrloi etc */
  		return;
  	} else {
  		printf("xmovei %s,%s", rnames[reg], p->n_right->n_name);
  		if (val)
  			printf("+" CONFMT, val);
  	}
  }
  
  /*
   * Return true if the constant can be bundled in an instruction (immediate).
   */
  static int
  oneinstr(NODE *p)
  {
  	if (p->n_name[0] != '\0')
  		return 0;
  	if ((p->n_lval & 0777777000000ULL) != 0)
  		return 0;
  	return 1;
  }
  
  /*
   * Emit a halfword or byte instruction, from OREG to REG.
   * Sign extension must also be done here.
   */
  static void
  emitshort(NODE *p)
  {
  	CONSZ off = p->n_lval;
  	TWORD type = p->n_type;
  	int reg = p->n_rval;
  	int issigned = !ISUNSIGNED(type);
  	int ischar = type == CHAR || type == UCHAR;
  	int reg1 = getlr(p, '1')->n_rval;
  
  	if (off < 0) { /* argument, use move instead */
  		printf("	move ");
  	} else if (off == 0 && p->n_name[0] == 0) {
  		printf("	ldb %s,%s\n", rnames[reg1], rnames[reg]);
  		/* XXX must sign extend here even if not necessary */
  		switch (type) {
  		case CHAR:
  			printf("	lsh %s,033\n", rnames[reg1]);
  			printf("	ash %s,-033\n", rnames[reg1]);
  			break;
  		case SHORT:
  			printf("	hrre %s,%s\n",
  			    rnames[reg1], rnames[reg1]);
  			break;
  		}
  		return;
  	} else if (ischar) {
  		if (off >= 0700000000000LL && p->n_name[0] != '\0') {
  			cerror("emitsh");
  			/* reg contains index integer */
  //			if (!istreg(reg))
  //				cerror("emitshort !istreg");
  			printf("	adjbp %s,[ .long 0%llo+%s ]\n",
  			    rnames[reg], off, p->n_name);
  			printf("	ldb ");
  			adrput(stdout, getlr(p, '1'));
  			printf(",%s\n", rnames[reg]);
  			goto signe;
  		}
  		printf("	ldb ");
  		adrput(stdout, getlr(p, '1'));
  		if (off)
  			printf(",[ .long 0%02o11%02o%06o ]\n",
  			    (int)(27-(9*(off&3))), reg, (int)off/4);
  		else
  			printf(",%s\n", rnames[reg]);
  signe:		if (issigned) {
  			printf("	lsh ");
  			adrput(stdout, getlr(p, '1'));
  			printf(",033\n	ash ");
  			adrput(stdout, getlr(p, '1'));
  			printf(",-033\n");
  		}
  		return;
  	} else {
  		printf("	h%cr%c ", off & 1 ? 'r' : 'l',
  		    issigned ? 'e' : 'z');
  	}
  	p->n_lval /= (ischar ? 4 : 2);
  	adrput(stdout, getlr(p, '1'));
  	putchar(',');
  	adrput(stdout, getlr(p, 'L'));
  	putchar('\n');
  }
  
  /*
   * Store a short from a register. Destination is a OREG.
   */
  static void
  storeshort(NODE *p)
  {
  	NODE *l = p->n_left;
  	CONSZ off = l->n_lval;
  	int reg = l->n_rval;
  	int ischar = BTYPE(p->n_type) == CHAR || BTYPE(p->n_type) == UCHAR;
  
  	if (l->n_op == NAME) {
  		if (ischar) {
  			printf("	dpb ");
  			adrput(stdout, getlr(p, 'R'));
  			printf(",[ .long 0%02o%010o+%s ]\n",
  			    070+((int)off&3), (int)(off/4), l->n_name);
  			return;
  		}
  		printf("	hr%cm ", off & 1 ? 'r' : 'l');
  		l->n_lval /= 2;
  		adrput(stdout, getlr(p, 'R'));
  		putchar(',');   
  		adrput(stdout, getlr(p, 'L'));
  		putchar('\n');
  		return;
  	}
  
  	if (off || reg == FPREG) { /* Can emit halfword instructions */
  		if (off < 0) { /* argument, use move instead */
  			printf("	movem ");
  		} else if (ischar) {
  			printf("	dpb ");
  			adrput(stdout, getlr(p, '1'));
  			printf(",[ .long 0%02o11%02o%06o ]\n",
  			    (int)(27-(9*(off&3))), reg, (int)off/4);
  			return;
  		} else {
  			printf("	hr%cm ", off & 1 ? 'r' : 'l');
  		}
  		l->n_lval /= 2;
  		adrput(stdout, getlr(p, 'R'));
  		putchar(',');
  		adrput(stdout, getlr(p, 'L'));
  	} else {
  		printf("	dpb ");
  		adrput(stdout, getlr(p, 'R'));
  		putchar(',');
  		l = getlr(p, 'L');
  		l->n_op = REG;
  		adrput(stdout, l);
  		l->n_op = OREG;
  	}
  	putchar('\n');
  }
  
  /*
   * Multiply a register with a constant.
   */
  static void     
  imuli(NODE *p)
  {
  	NODE *r = p->n_right;
  
  	if (r->n_lval >= 0 && r->n_lval <= 0777777) {
  		printf("	imuli ");
  		adrput(stdout, getlr(p, 'L'));
  		printf(",0%llo\n", r->n_lval);
  	} else {
  		printf("	imul ");
  		adrput(stdout, getlr(p, 'L'));
  		printf(",[ .long 0%llo ]\n", r->n_lval & 0777777777777LL);
  	}
  }
  
  /*
   * Divide a register with a constant.
   */
  static void     
  idivi(NODE *p)
  {
  	NODE *r = p->n_right;
  
  	if (r->n_lval >= 0 && r->n_lval <= 0777777) {
  		printf("	idivi ");
  		adrput(stdout, getlr(p, '1'));
  		printf(",0%llo\n", r->n_lval);
  	} else {
  		printf("	idiv ");
  		adrput(stdout, getlr(p, '1'));
  		printf(",[ .long 0%llo ]\n", r->n_lval & 0777777777777LL);
  	}
  }
  
  /*
   * move a constant into a register.
   */
  static void
  xmovei(NODE *p)
  {
  	/*
  	 * Trick: If this is an unnamed constant, just move it directly,
  	 * otherwise use xmovei to get section number.
  	 */
  	if (p->n_name[0] == '\0' || p->n_lval > 0777777) {
  		printf("	");
  		zzzcode(p, 'D');
  		putchar(' ');
  		adrput(stdout, getlr(p, '1'));
  		putchar(',');
  		zzzcode(p, 'E');
  	} else {
  		printf("	xmovei ");
  		adrput(stdout, getlr(p, '1'));
  		printf(",%s", p->n_name);
  		if (p->n_lval != 0)
  			printf("+0%llo", p->n_lval);
  	}
  	putchar('\n');
  }
  
  static void
  printcon(NODE *p) 
  {
  	CONSZ cz;
  
  	p = p->n_left;
  	if (p->n_lval >= 0700000000000LL) {
  		/* converted to pointer in clocal() */
  		conput(stdout, p);
  		return;
  	}
  	if (p->n_lval == 0 && p->n_name[0] == '\0') {
  		putchar('0');
  		return;
  	}
  	if (BTYPE(p->n_type) == CHAR || BTYPE(p->n_type) == UCHAR)
  		cz = (p->n_lval/4) | ((p->n_lval & 3) << 30);
  	else
  		cz = (p->n_lval/2) | (((p->n_lval & 1) + 5) << 30);
  	cz |= 0700000000000LL;
  	printf("0%llo", cz);
  	if (p->n_name[0] != '\0')
  		printf("+%s", p->n_name);
  }
  
  static void
  putcond(NODE *p)
  {               
  	char *c = 0; /* XXX gcc */
  
  	switch (p->n_op) {
  	case EQ: c = "e"; break;
  	case NE: c = "n"; break;
  	case LE: c = "le"; break;
  	case LT: c = "l"; break;
  	case GT: c = "g"; break;
  	case GE: c = "ge"; break;
  	default:
  		cerror("putcond");
  	}
  	printf("%s", c);
  }
  
  void
  zzzcode(NODE *p, int c)
  {
  	NODE *l;
  	CONSZ hval;
  
  	switch (c) {
  	case 'A': /* ildb right arg */
  		adrput(stdout, p->n_left->n_left);
  		break;
  
  	case 'B': /* remove from stack after subroutine call */
  		if (p->n_qual)
  			printf("	subi %%17,0%o\n", p->n_qual);
  		break;
  
  	case 'C':
  		constput(p);
  		break;
  
  	case 'D': /* Find out which type of const load insn to use */
  		if (p->n_op != ICON)
  			cerror("zzzcode not ICON");
  		if (p->n_name[0] == '\0') {
  			if ((p->n_lval <= 0777777) && (p->n_lval > 0))
  				printf("movei");
  			else if ((p->n_lval & 0777777) == 0)
  				printf("hrlzi");
  			else
  				printf("move");
  		} else
  			printf("move");
  		break;
  
  	case 'E': /* Print correct constant expression */
  		if (p->n_name[0] == '\0') {
  			if ((p->n_lval <= 0777777) && (p->n_lval > 0)){
  				printf("0%llo", p->n_lval);
  			} else if ((p->n_lval & 0777777) == 0) {
  				printf("0%llo", p->n_lval >> 18);
  			} else {
  				if (p->n_lval < 0)
  					printf("[ .long -0%llo]", -p->n_lval);
  				else
  					printf("[ .long 0%llo]", p->n_lval);
  			}
  		} else {
  			if (p->n_lval == 0)
  				printf("[ .long %s]", p->n_name);
  			else
  				printf("[ .long %s+0%llo]",
  				    p->n_name, p->n_lval);
  		}
  		break;
  
  	case 'G': /* structure argument */
  		printf("	addl %%17,0%o\n",
  		    attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0)/(SZINT/SZCHAR));
  		printf("	foo...\n");
  		break;
  
  	case 'P':
  		p = getlr(p, 'R');
  		/* FALLTHROUGH */
  	case 'O':
  		/*
  		 * Print long long expression.
  		 */
  		hval = gethval(p->n_lval);
  		printf("[ .long 0%llo,0%llo", hval,
  		    (p->n_lval & 0377777777777LL) | (hval & 0400000000000LL));
  		if (p->n_name[0] != '\0')
  			printf("+%s", p->n_name);
  		printf(" ]");
  		break;
  
  	case 'F': /* Print an "opsimp" instruction based on its const type */
  		hopcode(oneinstr(p->n_right) ? 'C' : 'R', p->n_op);
  		break;
  
  	case 'H': /* Print a small constant */
  		p = p->n_right;
  		printf("0%llo", p->n_lval & 0777777);
  		break;
  
  	case 'Q': /* two-param long long comparisions */
  		twollcomp(p);
  		break;
  
  	case 'R': /* two-param conditionals */
  		twocomp(p);
  		break;
  
  	case 'U':
  		emitshort(p);
  		break;
  		
  	case 'V':
  		storeshort(p);
  		break;
  
  	case 'Z':
  		ptrcomp(p);
  		break;
  
  	case 'a':
  		imuli(p);
  		break;
  
  	case 'b':
  		idivi(p);
  		break;
  
  	case 'c':
  		xmovei(p);
  		break;
  
  	case 'd':
  		printcon(p);
  		break;
  
  	case 'e':
  		putcond(p);
  		break;
  
  	case 'g':
  		if (p->n_right->n_op != OREG || p->n_right->n_lval != 0)
  			comperr("bad Zg oreg");
  		printf("%s", rnames[p->n_right->n_rval]);
  		break;
  
  #if 0
  	case '1': /* double upput */
  		p = getlr(p, '1');
  		p->n_rval += 2;
  		adrput(stdout, p);
  		p->n_rval -= 2;
  		break;
  #endif
  
  	case 'i': /* Write instruction for short load from name */
  		l = getlr(p, 'L');
  		printf("	h%cr%c %s,%s+" CONFMT "\n",
  		    l->n_lval & 1 ? 'r' : 'l',
  		    ISUNSIGNED(p->n_type) ? 'z' : 'e',
  		    rnames[getlr(p, '1')->n_rval],
  		    l->n_name, l->n_lval >> 1);
  		break;
  
  	default:
  		cerror("zzzcode %c", c);
  	}
  }
  
  /* set up temporary registers */
  void
  setregs(void)
  {
  	fregs = 7;	/* 7 free regs on PDP10 (1-7) */
  }
  
  /*ARGSUSED*/
  int
  rewfld(NODE *p)
  {
  	return(1);
  }
  
  int
  fldexpand(NODE *p, int cookie, char **cp)
  {
  	return 0;
  }
  
  int
  flshape(NODE *p)
  {
  	register int o = p->n_op;
  
  	return (o == REG || o == NAME || o == ICON ||
  		(o == OREG && (!R2TEST(p->n_rval) || tlen(p) == 1)));
  }
  
  /* INTEMP shapes must not contain any temporary registers */
  int
  shtemp(NODE *p)
  {
  	return(0);
  }
  
  int
  shumul(NODE *p, int order)
  {
  	register int o;
  
  	if (x2debug) {
  		int val;
  		printf("shumul(%p)\n", p);
  		eprint(p, 0, &val, &val);
  	}
  
  	o = p->n_op;
  #if 0
  	if (o == NAME || (o == OREG && !R2TEST(p->n_rval)) || o == ICON)
  		return(STARNM);
  #endif
  
  #if 0
  	if ((o == INCR) &&
  	    (p->n_left->n_op == REG && p->n_right->n_op == ICON) &&
  	    p->n_right->n_name[0] == '\0') {
  		switch (p->n_type) {
  			case CHAR|PTR:
  			case UCHAR|PTR:
  				o = 1;
  				break;
  
  			case SHORT|PTR:
  			case USHORT|PTR:
  				o = 2;
  				break;
  
  			case INT|PTR:
  			case UNSIGNED|PTR:
  			case LONG|PTR:
  			case ULONG|PTR:
  			case FLOAT|PTR:
  				o = 4;
  				break;
  
  			case DOUBLE|PTR:
  			case LONGLONG|PTR:
  			case ULONGLONG|PTR:
  				o = 8;
  				break;
  
  			default:
  				if (ISPTR(p->n_type) &&
  				     ISPTR(DECREF(p->n_type))) {
  					o = 4;
  					break;
  				} else
  					return(0);
  		}
  		return( 0);
  	}
  #endif
  	return( SRNOPE );
  }
  
  void
  adrcon(CONSZ val)
  {
  	cerror("adrcon: val %llo\n", val);
  }
  
  void
  conput(FILE *fp, NODE *p)
  {
  	switch (p->n_op) {
  	case ICON:
  		if (p->n_lval != 0) {
  			acon(fp, p);
  			if (p->n_name[0] != '\0')
  				fputc('+', fp);
  		}
  		if (p->n_name[0] != '\0')
  			fprintf(fp, "%s", p->n_name);
  		if (p->n_name[0] == '\0' && p->n_lval == 0)
  			fputc('0', fp);
  		return;
  
  	case REG:
  		fprintf(fp, "%s", rnames[p->n_rval]);
  		return;
  
  	default:
  		cerror("illegal conput");
  	}
  }
  
  /*ARGSUSED*/
  void
  insput(NODE *p)
  {
  	cerror("insput");
  }
  
  /*
   * Write out the upper address, like the upper register of a 2-register
   * reference, or the next memory location.
   */
  void
  upput(NODE *p, int size)
  {
  
  	size /= SZLONG;
  	switch (p->n_op) {
  	case REG:
  		printf("%s", rnames[p->n_rval + size]);
  		break;
  
  	case NAME:
  	case OREG:
  		p->n_lval += size;
  		adrput(stdout, p);
  		p->n_lval -= size;
  		break;
  	case ICON:
  		printf(CONFMT, p->n_lval >> (36 * size));
  		break;
  	default:
  		cerror("upput bad op %d size %d", p->n_op, size);
  	}
  }
  
  void
  adrput(FILE *fp, NODE *p)
  {
  	int r;
  	/* output an address, with offsets, from p */
  
  	if (p->n_op == FLD)
  		p = p->n_left;
  
  	switch (p->n_op) {
  
  	case NAME:
  		if (p->n_name[0] != '\0')
  			fputs(p->n_name, fp);
  		if (p->n_lval != 0)
  			fprintf(fp, "+" CONFMT, p->n_lval & 0777777777777LL);
  		return;
  
  	case OREG:
  		r = p->n_rval;
  #if 0
  		if (R2TEST(r)) { /* double indexing */
  			register int flags;
  
  			flags = R2UPK3(r);
  			if (flags & 1)
  				putc('*', fp);
  			if (flags & 4)
  				putc('-', fp);
  			if (p->n_lval != 0 || p->n_name[0] != '\0')
  				acon(p);
  			if (R2UPK1(r) != 100)
  				printf("(%s)", rnames[R2UPK1(r)]);
  			if (flags & 2)
  				putchar('+');
  			printf("[%s]", rnames[R2UPK2(r)]);
  			return;
  		}
  #endif
  		if (R2TEST(r))
  			cerror("adrput: unwanted double indexing: r %o", r);
  		if (p->n_rval != FPREG && p->n_lval < 0 && p->n_name[0]) {
  			fprintf(fp, "%s", p->n_name);
  			acon(fp, p);
  			fprintf(fp, "(%s)", rnames[p->n_rval]);
  			return;
  		}
  		if (p->n_lval < 0 && p->n_rval == FPREG && offarg) {
  			p->n_lval -= offarg-2; acon(fp, p); p->n_lval += offarg-2;
  		} else if (p->n_lval != 0)
  			acon(fp, p);
  		if (p->n_name[0] != '\0')
  			fprintf(fp, "%s%s", p->n_lval ? "+" : "", p->n_name);
  		if (p->n_lval > 0 && p->n_rval == FPREG && offlab)
  			fprintf(fp, "+" LABFMT, offlab);
  		if (p->n_lval < 0 && p->n_rval == FPREG && offarg)
  			fprintf(fp, "(017)");
  		else
  			fprintf(fp, "(%s)", rnames[p->n_rval]);
  		return;
  	case ICON:
  		/* addressable value of the constant */
  		if (p->n_lval > 0) {
  			acon(fp, p);
  			if (p->n_name[0] != '\0')
  				putc('+', fp);
  		}
  		if (p->n_name[0] != '\0')
  			fprintf(fp, "%s", p->n_name);
  		if (p->n_lval < 0) 
  			acon(fp, p);
  		if (p->n_name[0] == '\0' && p->n_lval == 0)
  			putc('0', fp);
  		return;
  
  	case REG:
  		fputs(rnames[p->n_rval], fp);
  		return;
  
  	default:
  		cerror("illegal address, op %d", p->n_op);
  		return;
  
  	}
  }
  
  /*
   * print out a constant
   */
  void
  acon(FILE *fp, NODE *p)
  {
  	if (p->n_lval < 0 && p->n_lval > -0777777777777ULL)
  		fprintf(fp, "-" CONFMT, -p->n_lval);
  	else
  		fprintf(fp, CONFMT, p->n_lval);
  }
  
  /*   printf conditional and unconditional branches */
  void
  cbgen(int o,int lab)
  {
  }
  
  /*
   * Do some local optimizations that must be done after optim is called.
   */
  static void
  optim2(NODE *p, void *arg)
  {
  	int op = p->n_op;
  	int m, ml;
  	NODE *l;
  
  	/* Remove redundant PCONV's */
  	if (op == PCONV) {
  		l = p->n_left;
  		m = BTYPE(p->n_type);
  		ml = BTYPE(l->n_type);
  		if ((m == INT || m == LONG || m == LONGLONG || m == FLOAT ||
  		    m == DOUBLE || m == STRTY || m == UNIONTY ||
  		    m == UNSIGNED || m == ULONG || m == ULONGLONG) &&
  		    (ml == INT || ml == LONG || ml == LONGLONG || ml == FLOAT ||
  		    ml == DOUBLE || ml == STRTY || ml == UNIONTY || 
  		    ml == UNSIGNED || ml == ULONG ||
  		    ml == ULONGLONG) && ISPTR(l->n_type)) {
  			*p = *l;
  			nfree(l);
  			op = p->n_op;
  		} else
  		if (ISPTR(DECREF(p->n_type)) &&
  		    (l->n_type == INCREF(STRTY))) {
  			*p = *l;
  			nfree(l);
  			op = p->n_op;
  		} else
  		if (ISPTR(DECREF(l->n_type)) &&
  		    (p->n_type == INCREF(INT) ||
  		    p->n_type == INCREF(STRTY) ||
  		    p->n_type == INCREF(UNSIGNED))) {
  			*p = *l;
  			nfree(l);
  			op = p->n_op;
  		}
  
  	}
  	/* Add constands, similar to the one in optim() */
  	if (op == PLUS && p->n_right->n_op == ICON) {
  		l = p->n_left;
  		if (l->n_op == PLUS && l->n_right->n_op == ICON &&
  		    (p->n_right->n_name[0] == '\0' ||
  		     l->n_right->n_name[0] == '\0')) {
  			l->n_right->n_lval += p->n_right->n_lval;
  			if (l->n_right->n_name[0] == '\0')
  				l->n_right->n_name = p->n_right->n_name;
  			nfree(p->n_right);
  			*p = *l;
  			nfree(l);
  		}
  	}
  
  	/* Convert "PTR undef" (void *) to "PTR uchar" */
  	/* XXX - should be done in MI code */
  	if (BTYPE(p->n_type) == VOID)
  		p->n_type = (p->n_type & ~BTMASK) | UCHAR;
  	if (op == ICON) {
  		if ((p->n_type == (PTR|CHAR) || p->n_type == (PTR|UCHAR))
  		    && p->n_lval == 0 && p->n_name[0] != '\0')
  			p->n_lval = 0700000000000LL;
  		if ((p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT))
  		    && p->n_lval == 0 && p->n_name[0] != '\0')
  			p->n_lval = 0750000000000LL;
  	}
  	if (op == MINUS) {
  		if ((p->n_left->n_type == (PTR|CHAR) ||
  		    p->n_left->n_type == (PTR|UCHAR)) &&
  		    (p->n_right->n_type == (PTR|CHAR) ||
  		    p->n_right->n_type == (PTR|UCHAR))) {
  			l = talloc();
  			l->n_op = SCONV;
  			l->n_type = INT;
  			l->n_left = p->n_right;
  			p->n_right = l;
  			l = talloc();
  			l->n_op = SCONV;
  			l->n_type = INT;
  			l->n_left = p->n_left;
  			p->n_left = l;
  		}
  	}
  }
  
  void
  myreader(struct interpass *ipole)
  {
  	struct interpass *ip;
  
  	DLIST_FOREACH(ip, ipole, qelem) {
  		if (ip->type != IP_NODE)
  			continue;
  		walkf(ip->ip_node, optim2, 0);
  	}
  
  	if (x2debug) {
  		printf("myreader final tree:\n");
  		printip(ipole);
  	}
  }
  
  /*
   * Remove some PCONVs after OREGs are created.
   */
  static void
  pconv2(NODE *p, void *arg)
  {
  	NODE *q;
  
  	if (p->n_op == PLUS) {
  		if (p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT)) {
  			if (p->n_right->n_op != ICON)
  				return;
  			if (p->n_left->n_op != PCONV)
  				return;
  			if (p->n_left->n_left->n_op != OREG)
  				return;
  			q = p->n_left->n_left;
  			nfree(p->n_left);
  			p->n_left = q;
  			/*
  			 * This will be converted to another OREG later.
  			 */
  		}
  	}
  }
  
  void
  mycanon(NODE *p)
  {
  	walkf(p, pconv2, 0);
  }
  
  /*
   * Remove last goto.
   */
  void
  myoptim(struct interpass *ip)
  {
  }
  
  /*
   * Return a class suitable for a specific type.
   */
  int
  gclass(TWORD t)
  {
  	return (szty(t) == 2 ? CLASSB : CLASSA);
  }
  
  static int
  argsiz(NODE *p)
  {
  	TWORD t = p->n_type;
  
  	if (t == STRTY || t == UNIONTY)
  		return attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0)/(SZINT/SZCHAR);
  	return szty(t);
  }
  
  /*
   * Calculate argument sizes.
   */
  void
  lastcall(NODE *p)
  {
          NODE *op = p;
          int size = 0;
  
          p->n_qual = 0;
          if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL)
                  return;
          for (p = p->n_right; p->n_op == CM; p = p->n_left)
  		if (p->n_right->n_op != ASSIGN)
                  	size += argsiz(p->n_right);
  	if (p->n_op != ASSIGN)
          	size += argsiz(p);
          op->n_qual = size; /* XXX */
  }
  
  void
  rmove(int s, int d, TWORD t)
  {
  	printf("	%smove %s,%s\n",
  	    (s > 017 ? "d" : ""), rnames[d], rnames[s]);
  }
  
  /*
   * For class c, find worst-case displacement of the number of
   * registers in the array r[] indexed by class.
   */
  int
  COLORMAP(int c, int *r)
  {
  	int num;
  
  	switch (c) {
  	case CLASSA:
  		/* there are 13 classa, so min 6 classb are needed to block */
  		num = r[CLASSB] * 2;
  		num += r[CLASSA];
  		return num < 13;
  	case CLASSB:
  		/* 7 classa may block all classb */
  		num = r[CLASSB] + r[CLASSA];
  		return num < 7;
  	}
  	comperr("COLORMAP");
  	return 0; /* XXX gcc */
  }
  
  /*
   * Target-dependent command-line options.
   */
  void
  mflags(char *str)
  {
  }
  
  /*
   * Do something target-dependent for xasm arguments.
   * Supposed to find target-specific constraints and rewrite them.
   */
  int
  myxasm(struct interpass *ip, NODE *p)
  {
  	return 0;
  }
  