#include "config.h"
#include "system.h"
#include "rtl.h"
#include "tree.h"
#include "toplev.h"

char *xcoff_bss_section_name;
char *xcoff_private_data_section_name;
char *xcoff_read_only_section_name;
char *xcoff_private_toc_section_name;
int lctoc0_inuse = 0;

/* support some of the StormC-pragmas. */
int pragmapriority = 8;

/* Default register names.  */
char storm_reg_names[][8] =
{
      "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",
      "r8",  "r9", "r10", "r11", "r12", "r13", "r14", "r15",
     "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
     "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
      "f0",  "f1",  "f2",  "f3",  "f4",  "f5",  "f6",  "f7",
      "f8",  "f9", "f10", "f11", "f12", "f13", "f14", "f15",
     "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
     "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
      "mq", "lr",  "ctr", "ap",
      "cr0",  "cr1",  "cr2",  "cr3",  "cr4",  "cr5",  "cr6",  "cr7",
  "fpmem"
};



/* Output a TOC entry.  We derive the entry name from what is
   being written.  */
void storm_output_toc (file, x, labelno)
     FILE *file;
     rtx x;
     int labelno;
{
  char buf[256];
  char *name = buf;
  char *real_name;
  rtx base = x;
  int offset = 0;

  if (TARGET_NO_TOC)
    abort ();

  /* if we're going to put a double constant in the TOC, make sure it's
     aligned properly when strict alignment is on. */
  if (GET_CODE (x) == CONST_DOUBLE
      && STRICT_ALIGNMENT
      && GET_MODE (x) == DFmode
      && ! (TARGET_NO_FP_IN_TOC && ! TARGET_MINIMAL_TOC)) {
    ASM_OUTPUT_ALIGN (file, 3);
  }


  if (TARGET_ELF && TARGET_MINIMAL_TOC)
    {
      ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "LC");
      fprintf (file, "%d = .-", labelno);
      ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "LCTOC");
      fputs ("1\n", file);
    }
  else if (TARGET_MINIMAL_TOC)
    {
      if (toc_initialized < 3)
      {
        fputs ("FILESCOPETOC__0:\n", file);
	    toc_initialized = 3;
	  }
	  fprintf (file, "LC__%d_:\n", labelno);
	  fprintf (file, ".set LC__%d,LC__%d_ - FILESCOPETOC__0\n", labelno, labelno);
    }
  else
    ASM_OUTPUT_INTERNAL_LABEL (file, "LC", labelno);

  /* Handle FP constants specially.  Note that if we have a minimal
     TOC, things we put here aren't actually in the TOC, so we can allow
     FP constants.  */
  if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == DFmode
      && ! (TARGET_NO_FP_IN_TOC && ! TARGET_MINIMAL_TOC))
    {
      REAL_VALUE_TYPE rv;
      long k[2];

      REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
      REAL_VALUE_TO_TARGET_DOUBLE (rv, k);
      if (TARGET_64BIT)
    {
      if (TARGET_MINIMAL_TOC)
        fprintf (file, "\t.llong 0x%lx%08lx\n", k[0], k[1]);
      else
        fprintf (file, "\t.tc FD_%lx_%lx[TC],0x%lx%08lx\n",
             k[0], k[1], k[0] & 0xffffffff, k[1] & 0xffffffff);
      return;
    }
      else
    {
      if (TARGET_MINIMAL_TOC)
        fprintf (file, "\t.long %ld\n\t.long %ld\n", k[0], k[1]);
      else
        fprintf (file, "\t.long %ld\n\t.long %ld\n", k[0], k[1]);
		//fprintf (file, "\t.tc FD_%lx_%lx[TC],%ld,%ld\n",
        //     k[0], k[1], k[0], k[1]);
      return;
    }
    }
  else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == SFmode
       && ! (TARGET_NO_FP_IN_TOC && ! TARGET_MINIMAL_TOC))
    {
      REAL_VALUE_TYPE rv;
      long l;

      REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
      REAL_VALUE_TO_TARGET_SINGLE (rv, l);

      if (TARGET_64BIT)
	{
	  if (TARGET_MINIMAL_TOC)
	    fprintf (file, "\t.llong 0x%lx00000000\n", l);
	  else
	    fprintf (file, "\t.tc FS_%lx[TC],0x%lx00000000\n", l, l);
	  return;
	}
      else
	{
	  fprintf (file, "\t.long 0x%lx\n", l);
	  return;
	}
    }
  else if (GET_MODE (x) == DImode
       && (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE)
       && ! (TARGET_NO_FP_IN_TOC && ! TARGET_MINIMAL_TOC))
    {
      HOST_WIDE_INT low;
      HOST_WIDE_INT high;

      if (GET_CODE (x) == CONST_DOUBLE)
    {
      low = CONST_DOUBLE_LOW (x);
      high = CONST_DOUBLE_HIGH (x);
    }
      else
#if HOST_BITS_PER_WIDE_INT == 32
    {
      low = INTVAL (x);
      high = (low < 0) ? ~0 : 0;
    }
#else
    {
          low = INTVAL (x) & 0xffffffff;
          high = (HOST_WIDE_INT) INTVAL (x) >> 32;
    }
#endif

      if (TARGET_64BIT)
    {
      if (TARGET_MINIMAL_TOC)
        fprintf (file, "\t.llong 0x%lx%08lx\n", (long)high, (long)low);
      else
        fprintf (file, "\t.tc ID_%lx_%lx[TC],0x%lx%08lx\n",
             (long)high, (long)low, (long)high, (long)low);
      return;
    }
      else
    {
      if (TARGET_MINIMAL_TOC)
        fprintf (file, "\t.long %ld\n\t.long %ld\n",
             (long)high, (long)low);
      else
        fprintf (file, "\t.tc ID_%lx_%lx[TC],%ld,%ld\n",
             (long)high, (long)low, (long)high, (long)low);
      return;
    }
    }

  if (GET_CODE (x) == CONST)
    {
      base = XEXP (XEXP (x, 0), 0);
      offset = INTVAL (XEXP (XEXP (x, 0), 1));
    }

  if (GET_CODE (base) == SYMBOL_REF)
    name = XSTR (base, 0);
  else if (GET_CODE (base) == LABEL_REF)
    ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (XEXP (base, 0)));
  else if (GET_CODE (base) == CODE_LABEL)
    ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (base));
  else
    abort ();

  STRIP_NAME_ENCODING (real_name, name);
	if (TARGET_MINIMAL_TOC)
	{
		fputs (TARGET_32BIT ? "\t.long " : "\t.llong ", file);
	}
	else
    {
		fputs ("\t.long ", file);
		RS6000_OUTPUT_BASENAME(file,name);

		if (offset < 0)
			fprintf (file, "-%d", - offset);
		else if (offset)
			fprintf (file, "+%d", offset);

		putc ('\n', file);
		return;
    }

	/* Currently C++ toc references to vtables can be emitted before it
	is decided whether the vtable is public or private.  If this is
	the case, then the linker will eventually complain that there is
	a TOC reference to an unknown section.  Thus, for vtables only,
	we emit the TOC reference to reference the symbol and not the
	section.  */
	if (!strncmp ("_vt.", name, 4))
	{
		RS6000_OUTPUT_BASENAME (file, name);
		if (offset < 0)
			fprintf (file, "%d", offset);
		else if (offset > 0)
			fprintf (file, "+%d", offset);
	}
	else
	{
		output_addr_const (file, x);
	}
	putc ('\n', file);
}


/* If defined, a C expression whose value is nonzero if IDENTIFIER
   with arguments ARGS is a valid machine specific attribute for TYPE.
   The attributes in ATTRIBUTES have previously been assigned to TYPE.  */
int storm_valid_type_attribute_p (type, attributes, identifier, args)
     tree type;
     tree attributes ATTRIBUTE_UNUSED;
     tree identifier;
     tree args;
{
	if (rs6000_valid_type_attribute_p(type, attributes, identifier, args))
		return 1;

	if (TREE_CODE (type) == FUNCTION_TYPE  ||  TREE_CODE (type) == METHOD_TYPE)
    {
		if (is_attribute_p("saveds", identifier))
			return 1;
	}
	return 0;
}

