#include <stdio.h>
#include "config.h"
#include "tree.h"
#include "rtl.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "real.h"
#include "insn-config.h"
#include "conditions.h"
#include "insn-flags.h"
#include "output.h"
#include "insn-attr.h"
#include "flags.h"
#include "expr.h"
#include "recog.h"

void
tsu_check_point ()
{
  ;
}

void
tsu_initial_elimination_offset (from_reg, to_reg, offset_var)
     int from_reg;
     int to_reg;
     int * offset_var;
{
  int reg;

  if (from_reg != FRAME_POINTER_REGNUM ||
      to_reg != STACK_POINTER_REGNUM) {
    abort ();
  }
#if 0
  * offset_var = get_frame_size ();
  
  for (reg = 0; reg < FIRST_PSEUDO_REGISTER; reg ++) {
    if (regs_ever_live [reg] && ! call_used_regs [reg]) {
      (* offset_var) ++;
    }
  }
#else
  * offset_var = 0;
#endif
}

void
tsu_function_prologue (file, size)
     FILE * file;
     int size;
{
  int reg, num;
  
  fprintf (file, "\t\t\t; begin function_prologue\n");
  
  num = 0;
  
  for (reg = 0; reg < FIRST_PSEUDO_REGISTER; reg ++) {
    if (regs_ever_live [reg] && ! call_used_regs [reg]) {
      num ++;
    }
  }
  
  if (num == 0 || num + size <= 32) {
    fprintf (file, "\tset\t%d, r15\n", current_function_pretend_args_size + num + size);
    fprintf (file, "\tsub\tr%d, r15, r%d\n", STACK_POINTER_REGNUM, STACK_POINTER_REGNUM);

    num = 0;
  
    for (reg = 0; reg < FIRST_PSEUDO_REGISTER; reg ++) {
      if (regs_ever_live [reg] && ! call_used_regs [reg]) {
	fprintf (file, "\tstore\tr%d + %d, r%d\n", STACK_POINTER_REGNUM, size + num ++, reg);
	fprintf (file, "\tnop\n");
      }
    }
  } else {
    fprintf (file, "\tset\t%d, r15\n", current_function_pretend_args_size + num);
    fprintf (file, "\tsub\tr%d, r15, r%d\n", STACK_POINTER_REGNUM, STACK_POINTER_REGNUM);

    num = 0;
  
    for (reg = 0; reg < FIRST_PSEUDO_REGISTER; reg ++) {
      if (regs_ever_live [reg] && ! call_used_regs [reg]) {
	fprintf (file, "\tstore\tr%d + %d, r%d\n", STACK_POINTER_REGNUM, num ++, reg);
	fprintf (file, "\tnop\n");
      }
    }

    fprintf (file, "\tset\t%d, r15\n", size);
    fprintf (file, "\tsub\tr%d, r15, r%d\n", STACK_POINTER_REGNUM, STACK_POINTER_REGNUM);
  }

  if (frame_pointer_needed) {
    fprintf (file, "\tmov\tr%d, r%d\n", STACK_POINTER_REGNUM, FRAME_POINTER_REGNUM);
  }
  
  fprintf (file, "\t\t\t; end function_prologue\n");
}

void
tsu_function_epilogue (file, size)
     FILE * file;
     int size;
{
  int reg, num;
  
  fprintf (file, "\t\t\t; begin function_epilogue\n");
  
  num = 0;
  
  for (reg = 0; reg < FIRST_PSEUDO_REGISTER; reg ++) {
    if (regs_ever_live [reg] && ! call_used_regs [reg]) {
      num ++;
    }
  }

  if (num == 0 || num + size <= 256) {
    num = 0;
    
    for (reg = 0; reg < FIRST_PSEUDO_REGISTER; reg ++) {
      if (regs_ever_live [reg] && ! call_used_regs [reg]) {
	fprintf (file, "\taddr\tr%d + %d\n", STACK_POINTER_REGNUM, size + num ++);
	fprintf (file, "\tnop\n");
	fprintf (file, "\tload\tr%d\n", reg);
      }
    }
    
    fprintf (file, "\tj\tr13\n");
    
    fprintf (file, "\tset\t%d, r15\n", current_function_pretend_args_size + num + size);
    fprintf (file, "\tadd\tr%d, r15, r%d\n", STACK_POINTER_REGNUM, STACK_POINTER_REGNUM);
  } else {
    fprintf (file, "\tset\t%d, r15\n", size);
    fprintf (file, "\tadd\tr%d, r15, r%d\n", STACK_POINTER_REGNUM, STACK_POINTER_REGNUM);

    num = 0;
    
    for (reg = 0; reg < FIRST_PSEUDO_REGISTER; reg ++) {
      if (regs_ever_live [reg] && ! call_used_regs [reg]) {
	fprintf (file, "\taddr\tr%d + %d\n", STACK_POINTER_REGNUM, num ++);
	fprintf (file, "\tnop\n");
	fprintf (file, "\tload\tr%d\n", reg);
      }
    }
    
    fprintf (file, "\tj\tr13\n");
    
    fprintf (file, "\tset\t%d, r15\n", current_function_pretend_args_size + num);
    fprintf (file, "\tadd\tr%d, r15, r%d\n", STACK_POINTER_REGNUM, STACK_POINTER_REGNUM);
  }

  fprintf (file, "\t\t\t; end function_epilogue\n");
}

int
tsu_legitimate_address_p (mode, x, strict, store)
     enum machine_mode mode;
     rtx x;
     int strict;
     int store;
{
#if 1
  int lim;

  lim = (store ? 32 : 256) - GET_MODE_SIZE (mode);
#endif

  if (GET_CODE (x) == REG &&
      REG_OK_FOR_BASE_P_STRICT (x, strict)) {
    return 1;
  }

  if (GET_CODE (x) == PLUS &&
      GET_CODE (XEXP (x, 0)) == REG &&
      GET_CODE (XEXP (x, 1)) == CONST_INT &&
      REG_OK_FOR_BASE_P_STRICT (XEXP (x, 0), strict)) {
#if 1
    if (INTVAL (XEXP (x, 1)) < 0 ||
	INTVAL (XEXP (x, 1)) > lim) {
      return 0;
    }
#endif

    return  1;
  }

  if (GET_CODE (x) == PLUS &&
      GET_CODE (XEXP (x, 0)) == CONST_INT &&
      GET_CODE (XEXP (x, 1)) == REG &&
      REG_OK_FOR_BASE_P_STRICT (XEXP (x, 1), strict)) {
#if 1
    if (INTVAL (XEXP (x, 0)) < 0 ||
	INTVAL (XEXP (x, 0)) > lim) {
      return 0;
    }
#endif

    return 1;
  }

  return 0;
}

void
tsu_print_operand (stream, x, code)
     FILE * stream;
     rtx x;
     int code;
{
  char str [100];
  REAL_VALUE_TYPE d;

  if (GET_CODE (x) == REG) {
    fprintf (stream, "%s", reg_names [REGNO (x)]);
  } else if (GET_CODE (x) == MEM) {
    output_address (XEXP (x, 0));
  } else if (GET_CODE (x) == CONST_DOUBLE) {
    REAL_VALUE_FROM_CONST_DOUBLE (d, x);
    REAL_VALUE_TO_DECIMAL (d, "%f", str);
    fprintf (stream, "%s", str);
  } else {
    output_addr_const (stream, x);
  }
}

void
tsu_print_operand_address (stream, x)
     FILE * stream;
     rtx x;
{
  if (GET_CODE (x) == REG) {
    fprintf (stream,
	     "%s + 0",
	     reg_names [REGNO (x)]);
  } else if (GET_CODE (x) == PLUS) {
    if (GET_CODE (XEXP (x, 0)) == CONST_INT &&
	GET_CODE (XEXP (x, 1)) == REG) {
      fprintf (stream,
	       "%s + %d",
	       reg_names [REGNO (XEXP (x, 1))],
	       INTVAL (XEXP (x, 0)));
    } else if (GET_CODE (XEXP (x, 0)) == REG &&
	       GET_CODE (XEXP (x, 1)) == CONST_INT) {
      fprintf (stream,
	       "%s + %d",
	       reg_names [REGNO (XEXP (x, 0))],
	       INTVAL (XEXP (x, 1)));
    } else {
      abort ();
    }
  } else {
    abort ();
  }
}

void
tsu_notice_update_cc (exp, insn)
     rtx exp;
     rtx insn;
{
  CC_STATUS_INIT;

  if (GET_CODE (exp) == SET) {
    if (REG_P (SET_DEST (exp))) {
      switch (GET_CODE (SET_SRC (exp))) {
      case MINUS:
	cc_status . value1 = SET_DEST (exp);
	cc_status . value2 = gen_rtx (COMPARE,
				      VOIDmode,
				      XEXP (SET_SRC (exp), 0),
				      XEXP (SET_SRC (exp), 1));
	break;
      case PLUS:
      case NEG:
      case AND:
      case IOR:
      case XOR:
      case NOT:
	cc_status . value1 = SET_DEST (exp);
	break;
      default:
	break;
      }
    }
  }
}

char *
tsu_fill_delay_slot (num, branch)
     int num;
     const char * branch;
{
  static char str [1000];
  int i;

  if (branch == NULL) {
    abort ();
  }

  sprintf (str,
	   "\t\t; begin delayed_insn"
	   "\n\t%s"
	   "\n\t\t\t; end delayed_insn"
	   "\n\t\t\t; with %d delay_slot(s)",
	   branch,
	   num);

  num -= dbr_sequence_length ();

  while (num -- > 0) {
    strcat (str, "\n\tnop");
  }

  if (dbr_sequence_length () == 0) {
    strcat (str, "\n\t\t\t; 0 delay_slot(s) filled");
  }

  return str;
}

int
tsu_next_cc0_user_is_signed (insn)
     rtx insn;
{
  rtx user, pat, exp, src, cond;

  user = next_cc0_user (insn);

  if (user == NULL_RTX ||
      GET_CODE (user) != JUMP_INSN) {
    abort ();
  }

  pat = PATTERN (user);

  if (GET_CODE (pat) == PARALLEL) {
    if (XVECLEN (pat, 0) == 0) {
      abort ();
    }

    exp = XVECEXP (pat, 0, 0);
  } else {
    exp = pat;
  }

  if (GET_CODE (exp) != SET) {
    abort ();
  }

  src = SET_SRC (exp);

  if (GET_CODE (src) != IF_THEN_ELSE) {
    abort ();
  }

  cond = XEXP (src, 0);

  switch (GET_CODE (cond)) {
  case EQ:
  case NE:
  case GTU:
  case LTU:
  case GEU:
  case LEU:
    return 0;
  case GT:
  case LT:
  case GE:
  case LE:
    return 1;
  default:
    abort ();
  }

  return -1;
}

int
tsu_const_ok_for_letter_p (value, c)
     int value;
     int c;
{
  switch (c) {
  default:
    return 0;
  }
}

void
tsu_asm_file_start (stream)
     FILE * stream;
{
  fprintf (stream, "%s\n", ASM_APP_OFF);
  fprintf (stream, ".address-data 0x0000\n");
}

int
tsu_align_up (num, align)
     int num;
     int align;
{
  if (align == 0) {
    return num;
  }

  return ((num - 1) / align + 1) * align;
}

int
tsu_same_register (reg1, reg2)
     rtx reg1;
     rtx reg2;
{
#if 0
  if (REGNO (reg1) == REGNO (reg2)) {
    return 1;
  }

  if (REGNO (reg1) < FIRST_PSEUDO_REGISTER ||
      REGNO (reg2) < FIRST_PSEUDO_REGISTER) {
    return 0;
  }

  if (reg_renumber == NULL) {
    return 0;
  }

  if (reg_renumber [REGNO (reg1)] < 0 ||
      reg_renumber [REGNO (reg2)] < 0) {
    return 0;
  }

  return reg_renumber [REGNO (reg1)] == reg_renumber [REGNO (reg2)];
#else
  return REGNO (reg1) == REGNO (reg2);
#endif
}

int
tsu_base_reg (x)
     rtx x;
{
  rtx y;

  if (GET_CODE (x) != MEM) {
    abort ();
  }

  y = XEXP (x, 0);

  if (GET_CODE (y) == REG) {
    return REGNO (y);
  } else if (GET_CODE (y) == PLUS) {
    if (GET_CODE (XEXP (y, 0)) == CONST_INT &&
	GET_CODE (XEXP (y, 1)) == REG) {
      return REGNO (XEXP (y, 1));
    } else if (GET_CODE (XEXP (y, 0)) == REG &&
	       GET_CODE (XEXP (y, 1)) == CONST_INT) {
      return REGNO (XEXP (y, 0));
    } else {
      abort ();
    }
  } else {
    abort ();
  }

  return 0;
}
