[gnu.gcc.bug] Porting to the icm3216

ian@sibyl.eleceng.ua.OZ (Ian Dall) (08/27/89)

GCC 1.35  ICM3216 Systems
-----------------------

I have been porting GCC to an ICM 3216. I have divided the changes I
suggest into two parts. This section has a patch to generate an
out-icm3216.c from the out-ns32k.c file as well as two new files,
tm-icm3216.h and xm-icm3216.h.

out-icm3216.c:
-------------

This is the same as out-ns32k.c except for the print_operand_addresses
function. I believe that the changes I have made should be integrated back
into out-ns32k.c for all ns32k based machines but I can't test those cases.
The distributed print_operand_addresses had some errors. It could emit

  (r1)

which is not legal. You have to emit

  0(r1)

It could also emit an extra level of indirection. i.e. It would output

  disp(0(r1)) or disp((r1))

when it should have emitted

  disp(r1)

As well as fixing these I arranged so that instead of outputting

  0(r1)[r4:d]

it outputs

  r1[r4:d]

which is the same and faster. Finally I changed it to cope with the NS
assembler syntax on the icm3216  (no "@"s). This is the only bit that I
think would need to be changed to put this function back into ns32k.out.
Also there was some code which I believe never gets executed which I have
added printf messages to. To date none of these have ever been generated
so I believe the relevent code could be removed.

xm-icm3216.h
------------

Needs not much explanation. Works for the icm3216 running NS Sys V.2.2

tm-icm3216.h
------------

Much of this file is just dealing with interfacing with the NS
assembler and with pcc compiled functions on this machine.

I have changed FUNCTION_EPILOGUE so it outputs

   addr disp(fp), r3
   lprd sp, r3
   enter ...

instead of just

   enter ...

This allows EXIT_IGNORE_STACK to be set and __builtin_alloca to be used.
I think it is a bit of a toss up whether this is a change for the better
or not. It probably depends on how much allocing you do.

The following is a shar archive of

  out.patch to make out-icm3216.
  xm-icm3216.h
  tm-icm3216.h


# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by  on Sun Aug 27 21:25:04 CST 1989
# Contents:  out.patch xm-icm3216.h tm-icm3216.h
 
echo x - out.patch
sed 's/^@//' > "out.patch" <<'@//E*O*F out.patch//'
*** config/out-ns32k.c	Thu Aug 17 14:36:33 1989
--- config/out-icm3216.c	Fri Aug 18 00:46:11 1989
***************
*** 222,228
  	if (REGNO (addr) == STACK_POINTER_REGNUM)
  	  { fprintf (file, "tos"); break; }
  	else
! 	  { fprintf (file, "%s", reg_names[REGNO (addr)]); break; }
        else if (CONSTANT_P (addr))
  	{ output_addr_const (file, addr); break; }
        else if (GET_CODE (addr) == MULT)

--- 222,231 -----
  	if (REGNO (addr) == STACK_POINTER_REGNUM)
  	  { fprintf (file, "tos"); break; }
  	else
! 	  {
! 	    fprintf (stderr, "** Dodgy reached**\n"); /*  Is this ever done? */
! 	    fprintf (file, "%s", reg_names[REGNO (addr)]); break;
! 	  }
        else if (CONSTANT_P (addr))
  	{ output_addr_const (file, addr); break; }
        else if (GET_CODE (addr) == MULT)
***************
*** 226,232
        else if (CONSTANT_P (addr))
  	{ output_addr_const (file, addr); break; }
        else if (GET_CODE (addr) == MULT)
! 	{ fprintf (file, "@0"); ireg = addr; goto print_index; }
        else if (GET_CODE (addr) == MEM)
  	{
  	  addr = XEXP (addr, 0);

--- 229,235 -----
        else if (CONSTANT_P (addr))
  	{ output_addr_const (file, addr); break; }
        else if (GET_CODE (addr) == MULT)
! 	{ fprintf (file, "0"); ireg = addr; goto print_index; }
        else if (GET_CODE (addr) == MEM)
  	{
  	  addr = XEXP (addr, 0);
***************
*** 230,235
        else if (GET_CODE (addr) == MEM)
  	{
  	  addr = XEXP (addr, 0);
  	  if (GET_CODE (addr) == PLUS)
  	    {
  	      offset = XEXP (addr, 1);

--- 233,239 -----
        else if (GET_CODE (addr) == MEM)
  	{
  	  addr = XEXP (addr, 0);
+ 	  fprintf (stderr, "** Dodgy reached**\n"); /*  Is this ever done? */
  	  if (GET_CODE (addr) == PLUS)
  	    {
  	      offset = XEXP (addr, 1);
***************
*** 247,253
        if (GET_CODE (addr) != PLUS)
  	abort ();
  
!       goto retry;
  
      case REG:
        if (REGNO (addr) == STACK_POINTER_REGNUM)

--- 251,261 -----
        if (GET_CODE (addr) != PLUS)
  	abort ();
  
! 	/* (MEM (PLUS ... )) */
!       fprintf (file, "0(");
!       output_address (addr);
!       fprintf (file, ")");
!       break;
  
      case REG:
        if (REGNO (addr) == STACK_POINTER_REGNUM)
***************
*** 262,268
        break;
  
      case MULT:
!       fprintf (file, "@0");
        ireg = addr; /* [rX:Y] */
        goto print_index;
        break;

--- 270,276 -----
        break;
  
      case MULT:
!       fprintf (file, "0");
        ireg = addr; /* [rX:Y] */
        goto print_index;
        break;
***************
*** 420,426
  #ifndef SEQUENT_ADDRESS_BUG
  	  putc ('(', file);
  	  paren_base_reg_printed = 0;
! 	  output_address (addr);
  #ifdef SEQUENT_BASE_REGS
  	  if (!paren_base_reg_printed)
  	    fprintf (file, "(sb)");

--- 428,442 -----
  #ifndef SEQUENT_ADDRESS_BUG
  	  putc ('(', file);
  	  paren_base_reg_printed = 0;
! 	  if (GET_CODE(addr) == MEM)
! 	    output_address (XEXP(addr,0));
! 	  else if (GET_CODE(addr) == REG)
! 	    fprintf (file, "%s", reg_names[REGNO(addr)]);
! 	  else
! 	    {
! 	      fprintf(stderr,"Attempt to create an illegal mode\n");
! 	      abort();
! 	    }
  #ifdef SEQUENT_BASE_REGS
  	  if (!paren_base_reg_printed)
  	    fprintf (file, "(sb)");
***************
*** 473,479
  	  break;
  	}
        if (ireg && breg && offset == const0_rtx)
! 	fprintf (file, "0(%s)", reg_names[REGNO (breg)]);
        else
  	{
  	  if (addr != 0)

--- 489,502 -----
  	  break;
  	}
        if (ireg && breg && offset == const0_rtx)
! 	/*
! 	  Here we should output rn[rm:scale] instead of
! 	  0(rn)[rm:scale] since it is equivalent and faster. -IWD-
! 	 */
! 	if (MEM_REG(breg))
! 	  fprintf (file, "0(%s)", reg_names[REGNO (breg)]);
! 	else
! 	  fprintf (file, "%s", reg_names[REGNO (breg)]);
        else
  	{
  	  if (addr != 0)
***************
*** 478,485
  	{
  	  if (addr != 0)
  	    {
! 	      if (ireg != 0 && breg == 0
! 		  && GET_CODE (offset) == CONST_INT) putc('@', file);
  	      output_addr_const (file, offset);
  	    }
  	  if (breg != 0)

--- 501,508 -----
  	{
  	  if (addr != 0)
  	    {
! 	   /* if (ireg != 0 && breg == 0
! 		  && GET_CODE (offset) == CONST_INT) putc('@', file); */
  	      output_addr_const (file, offset);
  	    }
  	  if (breg != 0)
***************
*** 522,527
        output_addr_const (file, addr);
      }
  }
  
  /* National 32032 shifting is so bad that we can get
     better performance in many common cases by using other

--- 545,552 -----
        output_addr_const (file, addr);
      }
  }
+ 
+ 
  
  /* National 32032 shifting is so bad that we can get
     better performance in many common cases by using other
@//E*O*F out.patch//
chmod u=rw,g=r,o=r out.patch
 
echo x - xm-icm3216.h
sed 's/^@//' > "xm-icm3216.h" <<'@//E*O*F xm-icm3216.h//'
/* Configuration for GNU C-compiler for ICM 3216.
   Copyright (C) 1987 Free Software Foundation, Inc.

This file is part of GNU CC.

GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.  No author or distributor
accepts responsibility to anyone for the consequences of using it
or for whether it serves any particular purpose or works at all,
unless he says so in writing.  Refer to the GNU CC General Public
License for full details.

Everyone is granted permission to copy, modify and redistribute
GNU CC, but only under the conditions described in the
GNU CC General Public License.   A copy of this license is
supposed to have been given to you along with GNU CC so you
can know your rights and responsibilities.  It should be in a
file named COPYING.  Among other things, the copyright notice
and this notice must be preserved on all copies.  */

/* #defines that need visibility everywhere.  */
#define FALSE 0
#define TRUE 1
#define USG
#define bcopy(a,b,s)	memcpy(b,a,s)
#define bzero(a,s)	memset(a,0,s)
#define bcmp		memcmp


/* Get machine dependancies actual target specific file.   */
#include "tm-icm3216.h"

/* This describes the machine the compiler is hosted on.  */
#define HOST_BITS_PER_CHAR 8
#define HOST_BITS_PER_SHORT 16
#define HOST_BITS_PER_INT 32
#define HOST_BITS_PER_LONG 32

/* Arguments to use with `exit'.  */
#define SUCCESS_EXIT_CODE 0
#define FATAL_EXIT_CODE 33
@//E*O*F xm-icm3216.h//
chmod u=rw,g=r,o=r xm-icm3216.h
 
echo x - tm-icm3216.h
sed 's/^@//' > "tm-icm3216.h" <<'@//E*O*F tm-icm3216.h//'
/* Definitions of target machine for GNU compiler.  ICM 3216 version.
   Copyright (C) 1987 Free Software Foundation, Inc.
   Contributed by Michael Tiemann (tiemann@mcc.com)

This file is part of GNU CC.

GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.  No author or distributor
accepts responsibility to anyone for the consequences of using it
or for whether it serves any particular purpose or works at all,
unless he says so in writing.  Refer to the GNU CC General Public
License for full details.

Everyone is granted permission to copy, modify and redistribute
GNU CC, but only under the conditions described in the
GNU CC General Public License.	 A copy of this license is
supposed to have been given to you along with GNU CC so you
can know your rights and responsibilities.  It should be in a
file named COPYING.  Among other things, the copyright notice
and this notice must be preserved on all copies.  */

#include "tm-ns32k.h"

/* Use GNX_V3 syntax for Absolute operands. (No "@") */
#define GNX_V3

/* The NS assembler and loader cant deal with  bsr <external symbol>
   instructions and we can't test if the operand is an external
   symbol, so we always use the jsr instruction
 */
#define JSR_ALWAYS

/* Print subsidiary information on the compiler version in use.	 */
#undef TARGET_VERSION
#define TARGET_VERSION printf (" (32000, ICM 3216 syntax)");
#define TARGET_DEFAULT 1
#undef DBX_DEBUGGING_INFO
#define SDB_DEBUGGING_INFO
/* DBX_REGISTER_NUMBER is also used by sdbout. We have to get the numbers
   the same as is used by SDB/GDB for the same register numbers. It is not
   easy to work out what SDB expects because CC only respects "register"
   for non floating declarations. The following confirms with the current
   GDB organisation for this machine.
 */
#undef DBX_REGISTER_NUMBER
#define DBX_REGISTER_NUMBER(REGNO) ((REGNO) < 8 ? (REGNO):\
 ((REGNO) < 16 ?\
 (REGNO) + 5: ((REGNO) == 16 ? 10: 9)))
#undef CALL_USED_REGISTERS
/* 1 for registers not available across function calls.
   These must include the FIXED_REGISTERS and also any
   registers that can be used without being saved.
   The latter must include the registers where values are returned
   and the register where structure-value addresses are passed.
   On the NS32k, EPILOGUE_SCRATCH is destroyed without being saved.
   Aside from that, you can include as many other registers as you like.  */
/* This conforms with pcc practice on this machine. Better performance might
   be achieved by making some (fp4 - fp7 ?) be saved in functions but this
   would be incompatible. */
#define CALL_USED_REGISTERS {1, 1, 1, 1, 0, 0, 0, 0, \
			     1, 1, 1, 1, 1, 1, 1, 1, \
			     1, 1}

#define EPILOGUE_SCRATCH 3
#undef FUNCTION_PROFILER
#define FUNCTION_PROFILER(FILE, LABELNO)  \
   fprintf (FILE, "\taddr .LP%d,r0\n\tjsr mcount\n", (LABELNO));    \
   data_section(); fprintf(FILE, ".data\n.align 2\n.LP%d:\t.double 0\n", (LABELNO))

#undef ASM_FILE_START
#define ASM_FILE_START(FILE) sdbout_filename ((FILE), main_input_filename)

/* This is how to output an internal numbered label where
   PREFIX is the class of label and NUM is the number within the class.	 */

#undef ASM_OUTPUT_INTERNAL_LABEL
#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM)	\
  fprintf (FILE, ".%s%d:\n", PREFIX, NUM)

/* This is how to store into the string LABEL
   the symbol_ref name of an internal numbered label where
   PREFIX is the class of label and NUM is the number within the class.
   This is suitable for output with `assemble_name' which uses a beginning
   "*" to mean just output the rest of LABEL rather than output
   ASM_OUTPUT_LABLEREF(STREAM, LABEL)	*/

#undef ASM_GENERATE_INTERNAL_LABEL
#define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM)	\
  sprintf (LABEL, "*.%s%d", PREFIX, NUM)

/* This is how to output an element of a case-vector that is absolute.
   (We do not use such vectors,
   but we must define this macro anyway.)  */

#undef ASM_OUTPUT_ADDR_VEC_ELT
#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE)  \
  fprintf (FILE, "\t.long .L%d\n", VALUE)

/* This is how to output an element of a case-vector that is relative.	*/
/* ** Notice that the second element is LI format! */
#undef ASM_OUTPUT_ADDR_DIFF_ELT
#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL)  \
  fprintf (FILE, "\t.word .L%d-.LI%d\n", VALUE, REL)

/* In NS assembler, double means a .double length INTEGER and .long means
   double precision FLOAT. i.e. The opposite usage to C */
/* This is how to output an assembler line defining a `double' constant.  */

#undef ASM_OUTPUT_DOUBLE
#define ASM_OUTPUT_DOUBLE(FILE,VALUE)  \
  fprintf (FILE, "\t.long 0d%.20e\n", (VALUE))

/* This is how to output an assembler line defining an `int' constant.	*/

#undef ASM_OUTPUT_INT
#define ASM_OUTPUT_INT(FILE,VALUE)  \
( fprintf (FILE, "\t.double "),			\
  output_addr_const (FILE, (VALUE)),		\
  fprintf (FILE, "\n"))

/* This is how to output an element of a case-vector that is absolute. */

#undef ASM_OUTPUT_ADDR_VEC_ELT
#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE)  \
  fprintf (FILE, "\t.long L%d\n", VALUE)

#undef ASM_OUTPUT_ALIGN
#define ASM_OUTPUT_ALIGN(FILE,LOG) \
  fprintf(FILE, "\t.align %d\n", 1 << (LOG))
#undef ASM_OUTPUT_LOCAL
#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED)  \
( fputs (".bss ", (FILE)),			\
  assemble_name ((FILE), (NAME)),		\
  fprintf ((FILE), ",%d,%d \n", (ROUNDED),     \
	   (BIGGEST_ALIGNMENT / BITS_PER_UNIT)))

#define ASM_OUTPUT_ASCII(FILE,PTR,LEN)	\
{							\
  char *s;						\
  int i;						\
  for (i = 0, s = (PTR); i < (LEN); s++, i++)		\
    {							\
      if ((i % 8) == 0)					\
	fputs ("\n\t.byte\t", (FILE));			\
      fprintf ((FILE), "%s0x%x", (i%8?",":""), (unsigned)*s); \
    }							\
  fputs ("\n", (FILE));					\
}

#undef PRINT_OPERAND_ADDRESS
#define PRINT_OPERAND_ADDRESS(FILE, ADDR)  print_operand_address(FILE, ADDR)


#define TARGET_MEM_FUNCTIONS

/* EXIT_IGNORE_STACK should be nonzero if, when returning from a function,
   the stack pointer does not matter.  The value is tested only in
   functions that have frame pointers.
   No definition is equivalent to always zero.	*/

#define EXIT_IGNORE_STACK 1

/* This macro generates the assembly code for function exit,
   on machines that need it.  If FUNCTION_EPILOGUE is not defined
   then individual return instructions are generated for each
   return statement.  Args are same as for FUNCTION_PROLOGUE.

   The function epilogue should not depend on the current stack pointer!
   It should use the frame pointer only.  This is mandatory because
   of alloca; we also take advantage of it to omit stack adjustments
   before returning.  */
#undef FUNCTION_EPILOGUE
#define FUNCTION_EPILOGUE(FILE, SIZE) \
{ extern int current_function_pops_args;			\
  extern int current_function_args_size;			\
  register int regno, n_regs_used = 0;				\
  int used_regs_buf[8], *bufp = used_regs_buf;			\
  int used_fregs_buf[8], *fbufp = used_fregs_buf;		\
  extern char call_used_regs[];					\
  *fbufp++ = -2;						\
  for (regno = 8; regno < 16; regno++)				\
    if (regs_ever_live[regno] && !call_used_regs[regno]) {	\
       *fbufp++ = regno; n_regs_used++;				\
    }								\
  fbufp--;							\
  for (regno = 0; regno < 8; regno++)				\
    if (regs_ever_live[regno] && ! call_used_regs[regno])	\
      {								\
	*bufp++ = regno; n_regs_used++;				\
      }								\
  if (frame_pointer_needed)					\
    {								\
      fprintf (FILE, "\taddr %d(fp), r%d\n\tlprd sp, r%d\n",	\
	       -(SIZE + n_regs_used * 4), EPILOGUE_SCRATCH,	\
	       EPILOGUE_SCRATCH);				\
    }								\
  while (fbufp > used_fregs_buf)				\
    {								\
      if ((*fbufp & 1) && fbufp[0] == fbufp[-1] + 1)		\
	{							\
	  fprintf (FILE, "\tmovl tos,f%d\n", fbufp[-1] - 8);	\
	  fbufp -= 2;						\
	}							\
      else fprintf (FILE, "\tmovf tos,f%d\n", *fbufp-- - 8);	\
    }								\
  if (frame_pointer_needed)					\
    {								\
      fprintf (FILE, "\texit [");				\
      while (bufp > used_regs_buf)				\
	{							\
	  fprintf (FILE, "r%d", *--bufp);			\
	  if (bufp > used_regs_buf)				\
	    fputc (',', FILE);					\
	}							\
      fprintf (FILE, "]\n");					\
    }								\
  else								\
    {								\
      while (bufp > used_regs_buf)				\
	fprintf (FILE, "\tmovd tos,r%d\n", *--bufp);		\
    }								\
  if (current_function_pops_args && current_function_args_size)	\
    fprintf (FILE, "\tret %d\n", current_function_args_size);	\
  else fprintf (FILE, "\tret 0\n"); }

/* If compiled with GNU C, use the built-in alloca */
#ifdef __GNUC__
#define alloca __builtin_alloca
#endif
@//E*O*F tm-icm3216.h//
chmod u=rw,g=r,o=r tm-icm3216.h
 
exit 0
-- 
Ian Dall     life (n). A sexually transmitted disease which afflicts
                       some people more severely than others.