text: /*	Id: order.c,v 1.22 2014/06/01 11:35:02 ragge Exp 	*/	
  /*	$NetBSD: order.c,v 1.1.1.4 2014/07/24 19:17:52 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 <strings.h>
  
  int canaddr(NODE *);
  
  /*
   * should the assignment op p be stored,
   * given that it lies as the right operand of o
   * (or the left, if o==UNARY MUL)
   */
  /*
  void
  stoasg(NODE *p, int o)
  {
  	if (x2debug)
  		printf("stoasg(%p, %o)\n", p, o);
  }
  */
  /* should we delay the INCR or DECR operation p */
  int
  deltest(NODE *p)
  {
  	return 0;
  }
  
  /*
   * Check if p can be autoincremented.
   * XXX - nothing can be autoincremented for now.
   */
  int
  autoincr(NODE *p)
  {
  	return 0;
  }
  
  /* is it legal to make an OREG or NAME entry which has an
   * offset of off, (from a register of r), if the
   * resulting thing had type t */
  int
  notoff(TWORD t, int r, CONSZ off, char *cp)
  {
  	return(0);  /* YES */
  }
  
  /*
   * Turn a UMUL-referenced node into OREG.
   */
  int
  offstar(NODE *p, int shape)
  {
  	if (x2debug)
  		printf("offstar(%p)\n", p);
  
  	if( p->n_op == PLUS || p->n_op == MINUS ){
  		if( p->n_right->n_op == ICON ){
  			geninsn(p->n_left, INBREG);
  			p->n_su = -1;
  			return 1;
  		}
  	}
  	geninsn(p, INBREG);
  	return 0;
  }
  
  /*
   * Shape matches for UMUL.  Cooperates with offstar().
   */
  int
  shumul(NODE *p, int shape)
  {
  //	NODE *l = p->n_left;
  
  #ifdef PCC_DEBUG
  	if (x2debug) {
  		printf("shumul(%p)\n", p);
  		fwalk(p, e2print, 0);
  	}
  #endif
  	/* XXX - fix */
  
  	/* Can only generate OREG of BREGs (or FB) */
  	if (p->n_op == REG && (isbreg(p->n_rval) || p->n_rval == FB))
  		return SROREG;
  #if 0
  	if ((p->n_op == PLUS || p->n_op == MINUS) &&
  	    (l->n_op == REG && (isbreg(l->n_rval) || l->n_rval == FB)) &&
  	    p->n_right->n_op == ICON)
  		return SOREG;
  	return 0;
  #else
  	return SROREG;
  #endif
  }
  
  /*
   * Rewrite increment/decrement operation.
   */
  int
  setincr(NODE *p)
  {
  	if (x2debug)
  		printf("setincr(%p)\n", p);
  
  	return(0);
  }
  
  /*
   * Rewrite operations on binary operators (like +, -, etc...).
   * Called as a result of table lookup.
   */
  int
  setbin(NODE *p)
  {
  
  	if (x2debug)
  		printf("setbin(%p)\n", p);
  	return 0;
  
  }
  
  /* setup for assignment operator */
  int
  setasg(NODE *p, int cookie)
  {
  	if (x2debug)
  		printf("setasg(%p)\n", p);
  	return(0);
  }
  
  /* setup for unary operator */
  int
  setuni(NODE *p, int cookie)
  {
  	return 0;
  }
  
  #if 0
  /*
   * register allocation for instructions with special preferences.
   */
  regcode
  regalloc(NODE *p, struct optab *q, int wantreg)
  {
  	regcode regc;
  
  	if (q->op == DIV || q->op == MOD) {
  		/*
  		 * 16-bit div.
  		 */
  		if (regblk[R0] & 1 || regblk[R2] & 1)
  			comperr("regalloc: needed regs inuse, node %p", p);
  		if (p->n_su & DORIGHT) {
  			regc = alloregs(p->n_right, A0);
  			if (REGNUM(regc) != A0) {
  				p->n_right = movenode(p->n_right, A0);
  				if ((p->n_su & RMASK) == ROREG) {
  					p->n_su &= ~RMASK;
  					p->n_su |= RREG;
  					p->n_right->n_su &= ~LMASK;
  					p->n_right->n_su |= LOREG;
  				}
  				freeregs(regc);
  				regblk[A0] |= 1;
  			}
  		}
  		regc = alloregs(p->n_left, R0);
  		if (REGNUM(regc) != R0) {
  			p->n_left = movenode(p->n_left, R0);
  			freeregs(regc);
  			regblk[R0] |= 1;
  		}
  		if ((p->n_su & RMASK) && !(p->n_su & DORIGHT)) {
  			regc = alloregs(p->n_right, A0);
  			if (REGNUM(regc) != A0) {
  				p->n_right = movenode(p->n_right, A0);
  				if ((p->n_su & RMASK) == ROREG) {
  					p->n_su &= ~RMASK;
  					p->n_su |= RREG;
  					p->n_right->n_su &= ~LMASK;
  					p->n_right->n_su |= LOREG;
  				}
  			}
  		}
  		regblk[A0] &= ~1;
  		regblk[R0] &= ~1;
  		regblk[R2] &= ~1;
  		if (q->op == DIV) {
  			MKREGC(regc, R0, 1);
  			regblk[R0] |= 1;
  		} else {
  			MKREGC(regc, R2, 1);
  			regblk[R2] |= 1;
  		}
  	} else
  		comperr("regalloc");
  	p->n_rall = REGNUM(regc);
  	return regc;
  }
  #endif
  
  /*
   * Special handling of some instruction register allocation.
   * - left is the register that left node wants.
   * - right is the register that right node wants.
   * - res is in which register the result will end up.
   * - mask is registers that will be clobbered.
   *
   *  XXX - Fix this function
   */
  struct rspecial *
  nspecial(struct optab *q)
  {
      switch (q->op) {
  
      case DIV:
      case MOD:
  	if(q->ltype & (TINT|TSHORT)){
  	    static struct rspecial s[] = {
  		{ NRES, R0 }, { NRES, R2}, { 0 } };
  	    return s;
  	}
  	/*
  	else if(q->ltype & TCHAR) {
  	    static struct rspecial s[] = {
  		{ NRES, R0L }, { NRES, R0H}, { 0 } };
  	    return s;
  	    }*/
  	break;
  
      case MUL:
  	/*
  	if(q->ltype & (TINT|TSHORT)){
  	    static struct rspecial s[] = {
  		{ NRES, R0 }, { NRES, R2}, { 0 } };
  	    return s;
  	    }*/
  	comperr("multiplication not implemented");
  	break;
  	
      default:
  	break;
      }
      comperr("nspecial entry %d", q - table);
      return 0; /* XXX gcc */
  }
  
  
  /*
   * Splitup a function call and give away its arguments first.
   * Calling convention used ("normal" in IAR syntax) is:
   * - 1-byte parameters in R0L if possible, otherwise in R0H.
   * - 2-byte pointers in A0.
   * - 2-byte non-pointers in R0 if no byte-size arguments are found in
   *   in the first 6 bytes of parameters, otherwise R2 or at last A0.
   * - 4-byte parameters in R2R0.
   */
  void
  gencall(NODE *p, NODE *prev)
  {
  	NODE *n = 0; /* XXX gcc */
  	static int storearg(NODE *);
  	int o = p->n_op;
  	int ty = optype(o);
  
  	if (ty == LTYPE)
  		return;
  
  	switch (o) {
  	case CALL:
  		/* swap arguments on some hardop-converted insns */
  		/* Normal call, just push args and be done with it */
  		p->n_op = UCALL;
  //printf("call\n");
  		/* Check if left can be evaluated directly */
  		if (p->n_left->n_op == UMUL) {
  			TWORD t = p->n_left->n_type;
  			int k = (freetemp(szty(t)));
  			NODE *n = mklnode(OREG, k, FB, t);
  			NODE *q = tcopy(n);
  			pass2_compile(ipnode(mkbinode(ASSIGN, n, p->n_left,t)));
  			p->n_left = q;
  		}
  		gencall(p->n_left, p);
  		p->n_rval = storearg(p->n_right);
  //printf("end call\n");
  		break;
  
  	case UFORTCALL:
  	case FORTCALL:
  		comperr("FORTCALL");
  
  	case USTCALL:
  	case STCALL:
  		/*
  		 * Structure return.  Look at the node above
  		 * to decide about buffer address:
  		 * - FUNARG, allocate space on stack, don't remove.
  		 * - nothing, allocate space on stack and remove.
  		 * - STASG, get the address of the left side as arg.
  		 * - FORCE, this ends up in a return, get supplied addr.
  		 * (this is not pretty, but what to do?)
  		 */
  		if (prev == NULL || prev->n_op == FUNARG) {
  			/* Create nodes to generate stack space */
  			n = mkbinode(ASSIGN, mklnode(REG, 0, STKREG, INT),
  			    mkbinode(MINUS, mklnode(REG, 0, STKREG, INT),
  			    mklnode(ICON, p->n_stsize, 0, INT), INT), INT);
  //printf("stsize %d\n", p->n_stsize);
  			pass2_compile(ipnode(n));
  		} else if (prev->n_op == STASG) {
  			n = prev->n_left;
  			if (n->n_op == UMUL)
  				n = nfree(n);
  			else if (n->n_op == NAME) {
  				n->n_op = ICON; /* Constant reference */
  				n->n_type = INCREF(n->n_type);
  			} else
  				comperr("gencall stasg");
  		} else if (prev->n_op == FORCE) {
  			; /* do nothing here */
  		} else {
  			comperr("gencall bad op %d", prev->n_op);
  		}
  
  		/* Deal with standard arguments */
  		gencall(p->n_left, p);
  		if (o == STCALL) {
  			p->n_op = USTCALL;
  			p->n_rval = storearg(p->n_right);
  		} else
  			p->n_rval = 0;
  		/* push return struct address */
  		if (prev == NULL || prev->n_op == FUNARG) {
  			n = mklnode(REG, 0, STKREG, INT);
  			if (p->n_rval)
  				n = mkbinode(PLUS, n,
  				    mklnode(ICON, p->n_rval, 0, INT), INT);
  			pass2_compile(ipnode(mkunode(FUNARG, n, 0, INT)));
  			if (prev == NULL)
  				p->n_rval += p->n_stsize/4;
  		} else if (prev->n_op == FORCE) {
  			/* return value for this function */
  			n = mklnode(OREG, 8, FPREG, INT);
  			pass2_compile(ipnode(mkunode(FUNARG, n, 0, INT)));
  			p->n_rval++;
  		} else {
  			pass2_compile(ipnode(mkunode(FUNARG, n, 0, INT)));
  			n = p;
  			*prev = *p;
  			nfree(n);
  		}
  //printf("end stcall\n");
  		break;
  
  	default:
  		if (ty != UTYPE)
  			gencall(p->n_right, p);
  		gencall(p->n_left, p);
  		break;
  	}
  }
  
  /*
   * Create separate node trees for function arguments.
   * This is partly ticky, the strange calling convention 
   * may cause a bunch of code reorganization here.
   */
  static int
  storearg(NODE *p)
  {
  	NODE *n, *q, **narry;
  	int nch, k, i, nn, rary[4];
  	int r0l, r0h, r2, a0, stk, sz;
  	TWORD t;
  	int maxrargs = 0;
  
  	if (p->n_op == CM)
  		maxrargs = p->n_stalign;
  
  	/* count the arguments */
  	for (i = 1, q = p; q->n_op == CM; q = q->n_left)
  		i++;
  	nn = i;
  
  	/* allocate array to store arguments */
  	narry = tmpalloc(sizeof(NODE *)*nn);
  
  	/* enter nodes into array */
  	for (q = p; q->n_op == CM; q = q->n_left)
  		narry[--i] = q->n_right;
  	narry[--i] = q;
  
  	/* free CM nodes */
  	for (q = p; q->n_op == CM; ) {
  		n = q->n_left;
  		nfree(q);
  		q = n;
  	}
  
  	/* count char args */
  	r0l = r0h = r2 = a0 = 0;
  	for (sz = nch = i = 0; i < nn && i < 6; i++) {
  		TWORD t = narry[i]->n_type;
  		if (sz >= 6)
  			break;
  		if (t == CHAR || t == UCHAR) {
  			nch++;
  			sz++;
  		} else if ((t >= SHORT && t <= UNSIGNED) ||
  		    t > BTMASK || t == FLOAT) {
  			sz += 2;
  		} else /* long, double */
  			sz += 4;
  			
  	}
  
  	/*
  	 * Now the tricky part. The parameters that should be on stack
  	 * must be found and pushed first, then the register parameters.
  	 * For the latter, be sure that evaluating them do not use any
  	 * registers where argument values already are inserted.
  	 * XXX - function pointers?
  	 * XXX foo(long a, char b) ???
  	 */
  	for (stk = 0; stk < 4; stk++) {
  		TWORD t;
  
  		if (stk == nn)
  			break;
  		t = narry[stk]->n_type;
  		if (ISFTN(DECREF(t)))
  			t = LONG;
  		switch (t) {
  		case CHAR: case UCHAR:
  			if (r0l) {
  				if (r0h)
  					break;
  				rary[stk] = R2; /* char talk for 'R0H' */
  				r0h = 1;
  			} else {
  				rary[stk] = R0;
  				r0l = 1;
  			}
  			continue;
  
  		case INT: case UNSIGNED:
  			if (r0l || nch) {
  				if (r2) {
  					if (a0)
  						break;
  					rary[stk] = A0;
  					a0 = 1;
  				} else {
  					rary[stk] = R2;
  					r2 = 1;
  				}
  			} else {
  				rary[stk] = R0;
  				r0l = r0h = 1;
  			}
  			continue;
  
  		case LONG: case ULONG:
  			if (r0l || r2)
  				break;
  			rary[stk] = R0;
  			r0l = r0h = r2 = 1;
  			continue;
  
  		default:
  			if (ISPTR(narry[stk]->n_type) &&
  			    !ISFTN(DECREF(narry[stk]->n_type))) {
  				if (a0) {
  					if (r0l || nch) {
  						if (r2)
  							break;
  						rary[stk] = R2;
  						r2 = 1;
  					} else {
  						rary[stk] = R0;
  						r0l = r0h = 1;
  					}
  				} else {
  					rary[stk] = A0;
  					a0 = 1;
  				}
  				continue;
  			}
  			break;
  		}
  		break;
  	}
  
  	/*
  	 * The arguments that must be on stack are stk->nn args.
  	 * Argument 0->stk-1 should be put in the rary[] register.
  	 */
  	for (sz = 0, i = nn-1; i >= stk; i--) { /* first stack args */
  		NODE nod;
  		pass2_compile(ipnode(mkunode(FUNARG,
  		    narry[i], 0, narry[i]->n_type)));
  		nod.n_type = narry[i]->n_type;
  		sz += tlen(&nod);
  	}
  	/* if param cannot be addressed directly, evaluate and put on stack */
  	for (i = 0; i < stk; i++) {
  
  		if (canaddr(narry[i]))
  			continue;
  		t = narry[i]->n_type;
  		k = (freetemp(szty(t)));
  		n = mklnode(OREG, k, FB, t);
  		q = tcopy(n);
  		pass2_compile(ipnode(mkbinode(ASSIGN, n, narry[i], t)));
  		narry[i] = q;
  	}
  	/* move args to registers */
  	for (i = 0; i < stk; i++) {
  		t = narry[i]->n_type;
  		pass2_compile(ipnode(mkbinode(ASSIGN, 
  		    mklnode(REG, 0, rary[i], t), narry[i], t)));
  	}
  	return sz;
  }
  
  /*
   * Tell if a register can hold a specific datatype.
   */
  #if 0
  int
  mayuse(int reg, TWORD type)
  {
  	return 1;  /* Everything is OK */
  }
  #endif
  
  #ifdef TAILCALL
  void
  mktailopt(struct interpass *ip1, struct interpass *ip2)
  {
  	extern int earlylab;
  	extern char *cftname;
  	char *fn;
  	NODE *p;
  
  	p = ip1->ip_node->n_left->n_left;
  	if (p->n_op == ICON) {
  		fn = p->n_name;
  		/* calling ourselves */
  		p = ip1->ip_node->n_left;
  		if (p->n_op == CALL) {
  			if (storearg(p->n_right))
  				comperr("too many args: fix mktailopt");
  			p->n_op = UCALL;
  		}
  		tfree(ip1->ip_node);
  		p = ip2->ip_node->n_left;
  		if (strcmp(fn, cftname)) {
  			/* Not us, must generate fake prologue */
  			ip1->type = IP_ASM;
  			ip1->ip_asm = "\tmov.w FB,SP\n\tpop.w FB\n";
  			pass2_compile(ip1);
  			p->n_lval = p->n_rval = 0;
  			p->n_name = fn;
  		} else
  			p->n_lval = earlylab;
  	} else {
  		pass2_compile(ip1);
  	}
  	pass2_compile(ip2);
  }
  #endif
  /*
   * Set registers "live" at function calls (like arguments in registers).
   * This is for liveness analysis of registers.
   */
  int *
  livecall(NODE *p)
  {
  	static int r[1] = { -1 }; /* Terminate with -1 */
  
  	return &r[0];
  }
  
  /*
   * Signal whether the instruction is acceptable for this target.
   */
  int
  acceptable(struct optab *op)
  {
  	return 1;
  }
  