This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Xtensa] new option for loading constants


This patch adds support for an alternative method of loading 32-bit constants 
on Xtensa processors.  The standard Xtensa ISA defines a PC-relative L32R 
load instruction to load values from constant pools.  The new method uses a 
CONST16 instruction that shifts the contents of a register left by 16 bits 
and then sets the low bits to a 16-bit immediate value, so that 2 CONST16 
instructions can load a 32-bit value.  The CONST16 instruction is currently 
not a standard option from Tensilica but can be implemented as a user-defined 
instruction.

As part of this change, I finally got around to generating the function 
prologues and epilogues as RTL.  I was also able to move the 
TARGET_MACHINE_DEPENDENT_REORG gunk into the code to expand the prologue.

The new CONST16-related code is disabled by default.  I ran the testsuite with 
the xtensa-elf target with CONST16 disabled; there were no new regressions.  
Committed on the mainline.

2003-05-13  Bob Wilson  <bob.wilson@acm.org>

        * config/xtensa/lib2funcs.S (TRAMPOLINE_SIZE): Change from 49 to 59.
        * config/xtensa/xtensa-config.h (XCHAL_HAVE_CONST16,
        XCHAL_HAVE_L32R): New.
        * config/xtensa/xtensa-protos.h (non_const_move_operand,
        xtensa_load_constant, xtensa_function_prologue,
        xtensa_function_epilogue): Delete prototypes.
        (xtensa_expand_prologue): New.
        * config/xtensa/xtensa.c (frame_size_const,
        TARGET_ASM_FUNCTION_PROLOGUE, TARGET_MACHINE_DEPENDENT_REORG,
        non_const_move_operand, xtensa_load_constant, xtensa_reorg,
        xtensa_function_prologue): Delete.
        (add_operand, xtensa_mem_offset): Formatting.
        (move_operand): If the const16 option is available, allow any SFmode
        and SImode constants.
        (xtensa_emit_move_sequence): Inline the former contents of
        xtensa_load_constant with modifications to handle the const16 option.
        (override_options): Add xtensa_char_to_class['W'] and set it to
        the general register class only if the const16 option is enabled.
        Fix formatting.  Disallow PIC when using the const16 option.
        (print_operand): Reorganize to switch on "letter" instead of the
        RTL code.  Add output_operand_lossage calls for invalid cases.
        Add support for 't' and 'b' letters.
        (xtensa_expand_prologue): New function to replace
        xtensa_function_prologue and xtensa_reorg.
        (xtensa_function_epilogue): Declare this as static.  Delete code
        to print the retw.n or retw instruction.
        (xtensa_return_addr): Use A0_REG instead of 0.
        (xtensa_rtx_costs): Add costs for using the const16 option.
        * config/xtensa/xtensa.h (MASK_CONST16, TARGET_CONST16): New.
        (TARGET_DEFAULT): Add CONST16 if L32R instructions not available.
        (TARGET_SWITCHES): Add "const16" and "no-const16".
        (REG_CLASS_FROM_LETTER): Add comment about new 'W' letter.
        (EXTRA_CONSTRAINT): Change 'T' constraint to only apply when not
        using the const16 option.
        (TRAMPOLINE_TEMPLATE): Rewrite to avoid hardwired use of l32r insn.
        (TRAMPOLINE_SIZE): Change from 49 to 59.
        (INITIALIZE_TRAMPOLINE): Adjust offsets to match new trampoline.
        (GO_IF_LEGITIMATE_ADDRESS): Do not allow constant pool addresses
        when using the const16 option.
        (PREDICATE_CODES): Delete non_const_move_operand.
        * config/xtensa/xtensa.md (define_constants): Add A1_REG, A8_REG, and
        UNSPECV_ENTRY.
        (movdi, movdf): If the source is a constant, always expand to a
        sequence of movsi insns.
        (movdi_internal, movdf_internal): Remove alternative using l32r insns.
        (movsi_internal, movsf_internal): Add alternative using const16 insns.
        (movsf): Add const16 support.
        (entry, prologue, epilogue): New.
        (set_frame_ptr): Add missing mode for unspec_volatile operation.
        Likewise for subsequent split pattern.
        * doc/invoke.texi (Option Summary, Xtensa Options): Document new
        "-mconst16" and "-mno-const16" options.

Index: gcc/config/xtensa/lib2funcs.S
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/xtensa/lib2funcs.S,v
retrieving revision 1.4
diff -c -3 -r1.4 lib2funcs.S
*** gcc/config/xtensa/lib2funcs.S	10 Apr 2003 16:57:58 -0000	1.4
--- gcc/config/xtensa/lib2funcs.S	14 May 2003 18:14:16 -0000
***************
*** 151,157 ****
     make sure that the modified instructions are loaded into the instruction
     fetch buffer. */
  	
! #define TRAMPOLINE_SIZE 49
  
  	.text
  	.align	4
--- 151,157 ----
     make sure that the modified instructions are loaded into the instruction
     fetch buffer. */
  	
! #define TRAMPOLINE_SIZE 59
  
  	.text
  	.align	4
Index: gcc/config/xtensa/xtensa-config.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/xtensa/xtensa-config.h,v
retrieving revision 1.2
diff -c -3 -r1.2 xtensa-config.h
*** gcc/config/xtensa/xtensa-config.h	12 Mar 2002 20:02:36 -0000	1.2
--- gcc/config/xtensa/xtensa-config.h	14 May 2003 18:14:16 -0000
***************
*** 1,5 ****
  /* Xtensa configuration settings.
!    Copyright (C) 2001,2002 Free Software Foundation, Inc.
     Contributed by Bob Wilson (bwilson@tensilica.com) at Tensilica.
  
  ** NOTE: This file was automatically generated by the Xtensa Processor
--- 1,5 ----
  /* Xtensa configuration settings.
!    Copyright (C) 2001,2002,2003 Free Software Foundation, Inc.
     Contributed by Bob Wilson (bwilson@tensilica.com) at Tensilica.
  
  ** NOTE: This file was automatically generated by the Xtensa Processor
***************
*** 27,32 ****
--- 27,34 ----
  
  #define XCHAL_HAVE_BE			1
  #define XCHAL_HAVE_DENSITY		1
+ #define XCHAL_HAVE_CONST16		0
+ #define XCHAL_HAVE_L32R			1
  #define XCHAL_HAVE_MAC16		0
  #define XCHAL_HAVE_MUL16		0
  #define XCHAL_HAVE_MUL32		0
Index: gcc/config/xtensa/xtensa-protos.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/xtensa/xtensa-protos.h,v
retrieving revision 1.9
diff -c -3 -r1.9 xtensa-protos.h
*** gcc/config/xtensa/xtensa-protos.h	14 May 2003 07:29:54 -0000	1.9
--- gcc/config/xtensa/xtensa-protos.h	14 May 2003 18:14:16 -0000
***************
*** 57,67 ****
  extern int smalloffset_double_mem_p PARAMS ((rtx));
  extern int constantpool_address_p PARAMS ((rtx));
  extern int constantpool_mem_p PARAMS ((rtx));
- extern int non_const_move_operand PARAMS ((rtx, enum machine_mode));
  extern int const_float_1_operand PARAMS ((rtx, enum machine_mode));
  extern int fpmem_offset_operand PARAMS ((rtx, enum machine_mode));
  extern void xtensa_extend_reg PARAMS ((rtx, rtx));
- extern void xtensa_load_constant PARAMS ((rtx, rtx));
  extern int branch_operator PARAMS ((rtx, enum machine_mode));
  extern int ubranch_operator PARAMS ((rtx, enum machine_mode));
  extern int boolean_operator PARAMS ((rtx, enum machine_mode));
--- 57,65 ----
***************
*** 110,117 ****
  extern void override_options PARAMS ((void));
  extern long compute_frame_size PARAMS ((int));
  extern int xtensa_frame_pointer_required PARAMS ((void));
! extern void xtensa_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
! extern void xtensa_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
  extern void order_regs_for_local_alloc PARAMS ((void));
  
  #endif /* !__XTENSA_PROTOS_H__ */
--- 108,114 ----
  extern void override_options PARAMS ((void));
  extern long compute_frame_size PARAMS ((int));
  extern int xtensa_frame_pointer_required PARAMS ((void));
! extern void xtensa_expand_prologue PARAMS ((void));
  extern void order_regs_for_local_alloc PARAMS ((void));
  
  #endif /* !__XTENSA_PROTOS_H__ */
Index: gcc/config/xtensa/xtensa.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/xtensa/xtensa.c,v
retrieving revision 1.32
diff -c -3 -r1.32 xtensa.c
*** gcc/config/xtensa/xtensa.c	14 May 2003 07:29:54 -0000	1.32
--- gcc/config/xtensa/xtensa.c	14 May 2003 18:14:16 -0000
***************
*** 198,226 ****
  static rtx fixup_subreg_mem PARAMS ((rtx x));
  static enum machine_mode xtensa_find_mode_for_size PARAMS ((unsigned));
  static struct machine_function * xtensa_init_machine_status PARAMS ((void));
- static void xtensa_reorg PARAMS ((void));
  static void printx PARAMS ((FILE *, signed int));
  static unsigned int xtensa_multibss_section_type_flags
    PARAMS ((tree, const char *, int));
  static void xtensa_select_rtx_section
    PARAMS ((enum machine_mode, rtx, unsigned HOST_WIDE_INT));
  static bool xtensa_rtx_costs PARAMS ((rtx, int, int, int *));
  
- static rtx frame_size_const;
  static int current_function_arg_words;
  static const int reg_nonleaf_alloc_order[FIRST_PSEUDO_REGISTER] =
    REG_ALLOC_ORDER;
  
- /* This macro generates the assembly code for function entry.
-    FILE is a stdio stream to output the code to.
-    SIZE is an int: how many units of temporary storage to allocate.
-    Refer to the array 'regs_ever_live' to determine which registers
-    to save; 'regs_ever_live[I]' is nonzero if register number I
-    is ever used in the function.  This macro is responsible for
-    knowing which registers should not be saved even if used.  */
- 
- #undef TARGET_ASM_FUNCTION_PROLOGUE
- #define TARGET_ASM_FUNCTION_PROLOGUE xtensa_function_prologue
  
  /* This macro generates the assembly code for function exit,
     on machines that need it.  If FUNCTION_EPILOGUE is not defined
--- 198,215 ----
  static rtx fixup_subreg_mem PARAMS ((rtx x));
  static enum machine_mode xtensa_find_mode_for_size PARAMS ((unsigned));
  static struct machine_function * xtensa_init_machine_status PARAMS ((void));
  static void printx PARAMS ((FILE *, signed int));
+ static void xtensa_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
  static unsigned int xtensa_multibss_section_type_flags
    PARAMS ((tree, const char *, int));
  static void xtensa_select_rtx_section
    PARAMS ((enum machine_mode, rtx, unsigned HOST_WIDE_INT));
  static bool xtensa_rtx_costs PARAMS ((rtx, int, int, int *));
  
  static int current_function_arg_words;
  static const int reg_nonleaf_alloc_order[FIRST_PSEUDO_REGISTER] =
    REG_ALLOC_ORDER;
  
  
  /* This macro generates the assembly code for function exit,
     on machines that need it.  If FUNCTION_EPILOGUE is not defined
***************
*** 244,252 ****
  #undef TARGET_ADDRESS_COST
  #define TARGET_ADDRESS_COST hook_int_rtx_0
  
- #undef TARGET_MACHINE_DEPENDENT_REORG
- #define TARGET_MACHINE_DEPENDENT_REORG xtensa_reorg
- 
  struct gcc_target targetm = TARGET_INITIALIZER;
  
  
--- 233,238 ----
***************
*** 412,419 ****
       enum machine_mode mode;
  {
    if (GET_CODE (op) == CONST_INT)
!     return (xtensa_simm8 (INTVAL (op)) ||
! 	    xtensa_simm8x256 (INTVAL (op)));
  
    return register_operand (op, mode);
  }
--- 398,404 ----
       enum machine_mode mode;
  {
    if (GET_CODE (op) == CONST_INT)
!     return (xtensa_simm8 (INTVAL (op)) || xtensa_simm8x256 (INTVAL (op)));
  
    return register_operand (op, mode);
  }
***************
*** 610,628 ****
       rtx op;
       enum machine_mode mode;
  {
!   if (register_operand (op, mode))
      return TRUE;
  
    /* Accept CONSTANT_P_RTX, since it will be gone by CSE1 and
       result in 0/1.  */
    if (GET_CODE (op) == CONSTANT_P_RTX)
      return TRUE;
  
!   if (GET_CODE (op) == CONST_INT)
!     return xtensa_simm12b (INTVAL (op));
  
!   if (GET_CODE (op) == MEM)
!     return memory_address_p (mode, XEXP (op, 0));
  
    return FALSE;
  }
--- 595,617 ----
       rtx op;
       enum machine_mode mode;
  {
!   if (register_operand (op, mode)
!       || memory_operand (op, mode))
      return TRUE;
  
+   if (mode == SFmode)
+     return TARGET_CONST16 && CONSTANT_P (op);
+ 
    /* Accept CONSTANT_P_RTX, since it will be gone by CSE1 and
       result in 0/1.  */
    if (GET_CODE (op) == CONSTANT_P_RTX)
      return TRUE;
  
!   if (GET_CODE (op) == CONST_INT && xtensa_simm12b (INTVAL (op)))
!     return TRUE;
  
!   if (mode == SImode)
!     return TARGET_CONST16 && CONSTANT_P (op);
  
    return FALSE;
  }
***************
*** 702,722 ****
  }
  
  
- int
- non_const_move_operand (op, mode)
-      rtx op;
-      enum machine_mode mode;
- {
-   if (register_operand (op, mode))
-     return 1;
-   if (GET_CODE (op) == SUBREG)
-     op = SUBREG_REG (op);
-   if (GET_CODE (op) == MEM)
-     return memory_address_p (mode, XEXP (op, 0));
-   return FALSE;
- }
- 
- 
  /* Accept the floating point constant 1 in the appropriate mode.  */
  
  int
--- 691,696 ----
***************
*** 778,809 ****
  }
  
  
- void
- xtensa_load_constant (dst, src)
-      rtx dst;
-      rtx src;
- {
-   enum machine_mode mode = GET_MODE (dst);
-   src = force_const_mem (SImode, src);
- 
-   /* PC-relative loads are always SImode so we have to add a SUBREG if that
-      is not the desired mode */
- 
-   if (mode != SImode)
-     {
-       if (register_operand (dst, mode))
- 	dst = simplify_gen_subreg (SImode, dst, mode, 0);
-       else
- 	{
- 	  src = force_reg (SImode, src);
- 	  src = gen_lowpart_SUBREG (mode, src);
- 	}
-     }
- 
-   emit_move_insn (dst, src);
- }
- 
- 
  int
  branch_operator (x, mode)
       rtx x;
--- 752,757 ----
***************
*** 899,906 ****
  	 moved in < "move_ratio" pieces.  The worst case is when the block is
  	 aligned but has a size of (3 mod 4) (does this happen?) so that the
  	 last piece requires a byte load/store.  */
!       return (xtensa_uimm8 (v) &&
! 	      xtensa_uimm8 (v + MOVE_MAX * LARGEST_MOVE_RATIO));
  
      case QImode:
        return xtensa_uimm8 (v);
--- 847,854 ----
  	 moved in < "move_ratio" pieces.  The worst case is when the block is
  	 aligned but has a size of (3 mod 4) (does this happen?) so that the
  	 last piece requires a byte load/store.  */
!       return (xtensa_uimm8 (v)
! 	      && xtensa_uimm8 (v + MOVE_MAX * LARGEST_MOVE_RATIO));
  
      case QImode:
        return xtensa_uimm8 (v);
***************
*** 1260,1266 ****
  
  
  /* Emit insns to move operands[1] into operands[0].
- 
     Return 1 if we have written out everything that needs to be done to
     do the move.  Otherwise, return 0 and the caller will emit the move
     normally.  */
--- 1208,1213 ----
***************
*** 1275,1282 ****
        && (GET_CODE (operands[1]) != CONST_INT
  	  || !xtensa_simm12b (INTVAL (operands[1]))))
      {
!       xtensa_load_constant (operands[0], operands[1]);
!       return 1;
      }
  
    if (!(reload_in_progress | reload_completed))
--- 1222,1248 ----
        && (GET_CODE (operands[1]) != CONST_INT
  	  || !xtensa_simm12b (INTVAL (operands[1]))))
      {
!       if (!TARGET_CONST16)
! 	operands[1] = force_const_mem (SImode, operands[1]);
! 
!       /* PC-relative loads are always SImode, and CONST16 is only
! 	 supported in the movsi pattern, so add a SUBREG for any other
! 	 (smaller) mode.  */
! 
!       if (mode != SImode)
! 	{
! 	  if (register_operand (operands[0], mode))
! 	    {
! 	      operands[0] = simplify_gen_subreg (SImode, operands[0], mode, 0);
! 	      emit_move_insn (operands[0], operands[1]);
! 	      return 1;
! 	    }
! 	  else
! 	    {
! 	      operands[1] = force_reg (SImode, operands[1]);
! 	      operands[1] = gen_lowpart_SUBREG (mode, operands[1]);
! 	    }
! 	}
      }
  
    if (!(reload_in_progress | reload_completed))
***************
*** 1299,1304 ****
--- 1265,1271 ----
    return 0;
  }
  
+ 
  static rtx
  fixup_subreg_mem (x)
       rtx x;
***************
*** 1848,1853 ****
--- 1815,1821 ----
    xtensa_char_to_class['C'] = ((TARGET_MUL16) ? GR_REGS: NO_REGS);
    xtensa_char_to_class['D'] = ((TARGET_DENSITY) ? GR_REGS: NO_REGS);
    xtensa_char_to_class['d'] = ((TARGET_DENSITY) ? AR_REGS: NO_REGS);
+   xtensa_char_to_class['W'] = ((TARGET_CONST16) ? GR_REGS: NO_REGS);
  
    /* Set up array giving whether a given register can hold a given mode.  */
    for (mode = VOIDmode;
***************
*** 1862,1869 ****
  	  int temp;
  
  	  if (ACC_REG_P (regno))
! 	    temp = (TARGET_MAC16 &&
! 		    (class == MODE_INT) && (size <= UNITS_PER_WORD));
  	  else if (GP_REG_P (regno))
  	    temp = ((regno & 1) == 0 || (size <= UNITS_PER_WORD));
  	  else if (FP_REG_P (regno))
--- 1830,1837 ----
  	  int temp;
  
  	  if (ACC_REG_P (regno))
! 	    temp = (TARGET_MAC16
! 		    && (class == MODE_INT) && (size <= UNITS_PER_WORD));
  	  else if (GP_REG_P (regno))
  	    temp = ((regno & 1) == 0 || (size <= UNITS_PER_WORD));
  	  else if (FP_REG_P (regno))
***************
*** 1879,1887 ****
  
    init_machine_status = xtensa_init_machine_status;
  
!   /* Check PIC settings.  There's no need for -fPIC on Xtensa and
!      some targets need to always use PIC.  */
!   if (flag_pic > 1 || (XTENSA_ALWAYS_PIC))
      flag_pic = 1;
  }
  
--- 1847,1865 ----
  
    init_machine_status = xtensa_init_machine_status;
  
!   /* Check PIC settings.  PIC is only supported when using L32R
!      instructions, and some targets need to always use PIC.  */
!   if (flag_pic && TARGET_CONST16)
!     error ("-f%s is not supported with CONST16 instructions",
! 	   (flag_pic > 1 ? "PIC" : "pic"));
!   else if (XTENSA_ALWAYS_PIC)
!     {
!       if (TARGET_CONST16)
! 	error ("PIC is required but not supported with CONST16 instructions");
!       flag_pic = 1;
!     }
!   /* There's no need for -fPIC (as opposed to -fpic) on Xtensa.  */
!   if (flag_pic > 1)
      flag_pic = 1;
  }
  
***************
*** 1918,1923 ****
--- 1896,1903 ----
     'D'  REG, print second register of double-word register operand
     'N'  MEM, print address of next word following a memory operand
     'v'  MEM, if memory reference is volatile, output a MEMW before it
+    't'  any constant, add "@h" suffix for top 16 bits
+    'b'  any constant, add "@l" suffix for bottom 16 bits
  */
  
  static void
***************
*** 1936,2029 ****
  
  
  void
! print_operand (file, op, letter)
       FILE *file;		/* file to write to */
!      rtx op;		/* operand to print */
       int letter;		/* %<letter> or 0 */
  {
!   enum rtx_code code;
! 
!   if (! op)
      error ("PRINT_OPERAND null pointer");
  
!   code = GET_CODE (op);
!   switch (code)
      {
!     case REG:
!     case SUBREG:
!       {
! 	int regnum = xt_true_regnum (op);
! 	if (letter == 'D')
! 	  regnum++;
! 	fprintf (file, "%s", reg_names[regnum]);
! 	break;
!       }
  
!     case MEM:
!       /* For a volatile memory reference, emit a MEMW before the
! 	 load or store.  */
!  	if (letter == 'v')
! 	  {
! 	    if (MEM_VOLATILE_P (op) && TARGET_SERIALIZE_VOLATILE)
! 	      fprintf (file, "memw\n\t");
! 	    break;
! 	  }
!  	else if (letter == 'N')
! 	  {
! 	    enum machine_mode mode;
! 	    switch (GET_MODE (op))
! 	      {
! 	      case DFmode: mode = SFmode; break;
! 	      case DImode: mode = SImode; break;
! 	      default: abort ();
! 	      }
! 	    op = adjust_address (op, mode, 4);
! 	  }
  
! 	output_address (XEXP (op, 0));
! 	break;
  
!     case CONST_INT:
!       switch (letter)
  	{
! 	case 'K':
! 	  {
! 	    int num_bits = 0;
! 	    unsigned val = INTVAL (op);
! 	    while (val & 1)
! 	      {
! 		num_bits += 1;
! 		val = val >> 1;
! 	      }
! 	    if ((val != 0) || (num_bits == 0) || (num_bits > 16))
! 	      fatal_insn ("invalid mask", op);
  
! 	    fprintf (file, "%d", num_bits);
! 	    break;
! 	  }
  
! 	case 'L':
! 	  fprintf (file, "%ld", (32 - INTVAL (op)) & 0x1f);
! 	  break;
  
! 	case 'R':
! 	  fprintf (file, "%ld", INTVAL (op) & 0x1f);
! 	  break;
  
! 	case 'x':
! 	  printx (file, INTVAL (op));
! 	  break;
  
! 	case 'd':
! 	default:
! 	  fprintf (file, "%ld", INTVAL (op));
! 	  break;
  
  	}
        break;
  
      default:
!       output_addr_const (file, op);
      }
  }
  
--- 1916,2061 ----
  
  
  void
! print_operand (file, x, letter)
       FILE *file;		/* file to write to */
!      rtx x;			/* operand to print */
       int letter;		/* %<letter> or 0 */
  {
!   if (!x)
      error ("PRINT_OPERAND null pointer");
  
!   switch (letter)
      {
!     case 'D':
!       if (GET_CODE (x) == REG || GET_CODE (x) == SUBREG)
! 	fprintf (file, "%s", reg_names[xt_true_regnum (x) + 1]);
!       else
! 	output_operand_lossage ("invalid %%D value");
!       break;
  
!     case 'v':
!       if (GET_CODE (x) == MEM)
! 	{
! 	  /* For a volatile memory reference, emit a MEMW before the
! 	     load or store.  */
! 	  if (MEM_VOLATILE_P (x) && TARGET_SERIALIZE_VOLATILE)
! 	    fprintf (file, "memw\n\t");
! 	}
!       else
! 	output_operand_lossage ("invalid %%v value");
!       break;
  
!     case 'N':
!       if (GET_CODE (x) == MEM
! 	  && (GET_MODE (x) == DFmode || GET_MODE (x) == DImode))
! 	{
! 	  x = adjust_address (x, GET_MODE (x) == DFmode ? SFmode : SImode, 4);
! 	  output_address (XEXP (x, 0));
! 	}
!       else
! 	output_operand_lossage ("invalid %%N value");
!       break;
  
!     case 'K':
!       if (GET_CODE (x) == CONST_INT)
  	{
! 	  int num_bits = 0;
! 	  unsigned val = INTVAL (x);
! 	  while (val & 1)
! 	    {
! 	      num_bits += 1;
! 	      val = val >> 1;
! 	    }
! 	  if ((val != 0) || (num_bits == 0) || (num_bits > 16))
! 	    fatal_insn ("invalid mask", x);
  
! 	  fprintf (file, "%d", num_bits);
! 	}
!       else
! 	output_operand_lossage ("invalid %%K value");
!       break;
  
!     case 'L':
!       if (GET_CODE (x) == CONST_INT)
! 	fprintf (file, "%ld", (32 - INTVAL (x)) & 0x1f);
!       else
! 	output_operand_lossage ("invalid %%L value");
!       break;
  
!     case 'R':
!       if (GET_CODE (x) == CONST_INT)
! 	fprintf (file, "%ld", INTVAL (x) & 0x1f);
!       else
! 	output_operand_lossage ("invalid %%R value");
!       break;
  
!     case 'x':
!       if (GET_CODE (x) == CONST_INT)
! 	printx (file, INTVAL (x));
!       else
! 	output_operand_lossage ("invalid %%x value");
!       break;
  
!     case 'd':
!       if (GET_CODE (x) == CONST_INT)
! 	fprintf (file, "%ld", INTVAL (x));
!       else
! 	output_operand_lossage ("invalid %%d value");
!       break;
  
+     case 't':
+     case 'b':
+       if (GET_CODE (x) == CONST_INT)
+ 	{
+ 	  printx (file, INTVAL (x));
+ 	  fputs (letter == 't' ? "@h" : "@l", file);
+ 	}
+       else if (GET_CODE (x) == CONST_DOUBLE)
+ 	{
+ 	  REAL_VALUE_TYPE r;
+ 	  REAL_VALUE_FROM_CONST_DOUBLE (r, x);
+ 	  if (GET_MODE (x) == SFmode)
+ 	    {
+ 	      long l;
+ 	      REAL_VALUE_TO_TARGET_SINGLE (r, l);
+ 	      fprintf (file, "0x%08lx@%c", l, letter == 't' ? 'h' : 'l');
+ 	    }
+ 	  else
+ 	    output_operand_lossage ("invalid %%t/%%b value");
+ 	}
+       else if (GET_CODE (x) == CONST)
+ 	{
+ 	  /* X must be a symbolic constant on ELF.  Write an expression
+ 	     suitable for 'const16' that sets the high or low 16 bits.  */
+ 	  if (GET_CODE (XEXP (x, 0)) != PLUS
+ 	      || (GET_CODE (XEXP (XEXP (x, 0), 0)) != SYMBOL_REF
+ 		  && GET_CODE (XEXP (XEXP (x, 0), 0)) != LABEL_REF)
+ 	      || GET_CODE (XEXP (XEXP (x, 0), 1)) != CONST_INT)
+ 	    output_operand_lossage ("invalid %%t/%%b value");
+ 	  print_operand (file, XEXP (XEXP (x, 0), 0), 0);
+ 	  fputs (letter == 't' ? "@h" : "@l", file);
+ 	  /* There must be a non-alphanumeric character between 'h' or 'l'
+ 	     and the number.  The '-' is added by print_operand() already.  */
+ 	  if (INTVAL (XEXP (XEXP (x, 0), 1)) >= 0)
+ 	    fputs ("+", file);
+ 	  print_operand (file, XEXP (XEXP (x, 0), 1), 0);
+ 	}
+       else
+ 	{ 
+ 	  output_addr_const (file, x);
+ 	  fputs (letter == 't' ? "@h" : "@l", file);
  	}
        break;
  
      default:
!       if (GET_CODE (x) == REG || GET_CODE (x) == SUBREG)
! 	fprintf (file, "%s", reg_names[xt_true_regnum (x)]);
!       else if (GET_CODE (x) == MEM)
! 	output_address (XEXP (x, 0));
!       else if (GET_CODE (x) == CONST_INT)
! 	fprintf (file, "%ld", INTVAL (x));
!       else
! 	output_addr_const (file, x);
      }
  }
  
***************
*** 2191,2319 ****
  }
  
  
! /* If the stack frame size is too big to fit in the immediate field of
!    the ENTRY instruction, we need to store the frame size in the
!    constant pool.  However, the code in xtensa_function_prologue runs too
!    late to be able to add anything to the constant pool.  Since the
!    final frame size isn't known until reload is complete, this seems
!    like the best place to do it.
  
!    There may also be some fixup required if there is an incoming argument
!    in a7 and the function requires a frame pointer. */
  
! static void
! xtensa_reorg ()
! {
!   rtx first, insn, set_frame_ptr_insn = 0;
!     
!   unsigned long tsize = compute_frame_size (get_frame_size ());
!   first = get_insns ();
!   if (tsize < (1 << (12+3)))
!     frame_size_const = 0;
    else
      {
!       frame_size_const = force_const_mem (SImode, GEN_INT (tsize - 16));;
! 
!       /* make sure the constant is used so it doesn't get eliminated
! 	 from the constant pool */
!       emit_insn_before (gen_rtx_USE (SImode, frame_size_const), first);
      }
  
!   if (!frame_pointer_needed)
!     return;
! 
!   /* Search all instructions, looking for the insn that sets up the
!      frame pointer.  This search will fail if the function does not
!      have an incoming argument in $a7, but in that case, we can just
!      set up the frame pointer at the very beginning of the
!      function.  */
! 
!   for (insn = first; insn; insn = NEXT_INSN (insn))
      {
!       rtx pat;
  
!       if (!INSN_P (insn))
! 	continue;
  
!       pat = PATTERN (insn);
!       if (GET_CODE (pat) == SET
! 	  && GET_CODE (SET_SRC (pat)) == UNSPEC_VOLATILE
! 	  && (XINT (SET_SRC (pat), 1) == UNSPECV_SET_FP))
! 	{
! 	  set_frame_ptr_insn = insn;
! 	  break;
  	}
-     }
  
!   if (set_frame_ptr_insn)
!     {
!       /* for all instructions prior to set_frame_ptr_insn, replace
! 	 hard_frame_pointer references with stack_pointer */
!       for (insn = first; insn != set_frame_ptr_insn; insn = NEXT_INSN (insn))
! 	{
! 	  if (INSN_P (insn))
! 	    PATTERN (insn) = replace_rtx (copy_rtx (PATTERN (insn)),
! 					  hard_frame_pointer_rtx,
! 					  stack_pointer_rtx);
  	}
!     }
!   else
!     {
!       /* emit the frame pointer move immediately after the NOTE that starts
! 	 the function */
!       emit_insn_after (gen_movsi (hard_frame_pointer_rtx,
! 				  stack_pointer_rtx), first);
!     }
! }
! 
! 
! /* Set up the stack and frame (if desired) for the function.  */
! 
! void
! xtensa_function_prologue (file, size)
!      FILE *file;
!      HOST_WIDE_INT size ATTRIBUTE_UNUSED;
! {
!   unsigned long tsize = compute_frame_size (get_frame_size ());
! 
!   if (frame_pointer_needed)
!     fprintf (file, "\t.frame\ta7, %ld\n", tsize);
!   else
!     fprintf (file, "\t.frame\tsp, %ld\n", tsize);
!  
! 
!   if (tsize < (1 << (12+3)))
!     {
!       fprintf (file, "\tentry\tsp, %ld\n", tsize);
!     }
!   else
!     {
!       fprintf (file, "\tentry\tsp, 16\n");
! 
!       /* use a8 as a temporary since a0-a7 may be live */
!       fprintf (file, "\tl32r\ta8, ");
!       print_operand (file, frame_size_const, 0);
!       fprintf (file, "\n\tsub\ta8, sp, a8\n");
!       fprintf (file, "\tmovsp\tsp, a8\n");
      }
  }
  
  
! /* Do any necessary cleanup after a function to restore
!    stack, frame, and regs.  */
  
  void
  xtensa_function_epilogue (file, size)
!      FILE *file;
       HOST_WIDE_INT size ATTRIBUTE_UNUSED;
  {
-   rtx insn = get_last_insn ();
-   /* If the last insn was a BARRIER, we don't have to write anything.  */
-   if (GET_CODE (insn) == NOTE)
-     insn = prev_nonnote_insn (insn);
-   if (insn == 0 || GET_CODE (insn) != BARRIER)
-     fprintf (file, TARGET_DENSITY ? "\tretw.n\n" : "\tretw\n");
- 
    xtensa_current_frame_size = 0;
  }
  
--- 2223,2307 ----
  }
  
  
! void
! xtensa_expand_prologue ()
! {
!   HOST_WIDE_INT total_size;
!   rtx size_rtx;
  
!   total_size = compute_frame_size (get_frame_size ());
!   size_rtx = GEN_INT (total_size);
  
!   if (total_size < (1 << (12+3)))
!     emit_insn (gen_entry (size_rtx, size_rtx));
    else
      {
!       /* Use a8 as a temporary since a0-a7 may be live.  */
!       rtx tmp_reg = gen_rtx_REG (Pmode, A8_REG);
!       emit_insn (gen_entry (size_rtx, GEN_INT (MIN_FRAME_SIZE)));
!       emit_move_insn (tmp_reg, GEN_INT (total_size - MIN_FRAME_SIZE));
!       emit_insn (gen_subsi3 (tmp_reg, stack_pointer_rtx, tmp_reg));
!       emit_move_insn (stack_pointer_rtx, tmp_reg);
      }
  
!   if (frame_pointer_needed)
      {
!       rtx first, insn, set_frame_ptr_insn = 0;
  
!       push_topmost_sequence ();
!       first = get_insns ();
!       pop_topmost_sequence ();
  
!       /* Search all instructions, looking for the insn that sets up the
! 	 frame pointer.  This search will fail if the function does not
! 	 have an incoming argument in $a7, but in that case, we can just
! 	 set up the frame pointer at the very beginning of the
! 	 function.  */
! 
!       for (insn = first; insn; insn = NEXT_INSN (insn))
! 	{
! 	  rtx pat;
! 
! 	  if (!INSN_P (insn))
! 	    continue;
! 
! 	  pat = PATTERN (insn);
! 	  if (GET_CODE (pat) == SET
! 	      && GET_CODE (SET_SRC (pat)) == UNSPEC_VOLATILE
! 	      && (XINT (SET_SRC (pat), 1) == UNSPECV_SET_FP))
! 	    {
! 	      set_frame_ptr_insn = insn;
! 	      break;
! 	    }
  	}
  
!       if (set_frame_ptr_insn)
! 	{
! 	  /* For all instructions prior to set_frame_ptr_insn, replace
! 	     hard_frame_pointer references with stack_pointer.  */
! 	  for (insn = first;
! 	       insn != set_frame_ptr_insn;
! 	       insn = NEXT_INSN (insn))
! 	    {
! 	      if (INSN_P (insn))
! 		PATTERN (insn) = replace_rtx (copy_rtx (PATTERN (insn)),
! 					      hard_frame_pointer_rtx,
! 					      stack_pointer_rtx);
! 	    }
  	}
!       else
! 	emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);
      }
  }
  
  
! /* Clear variables at function end.  */
  
  void
  xtensa_function_epilogue (file, size)
!      FILE *file ATTRIBUTE_UNUSED;
       HOST_WIDE_INT size ATTRIBUTE_UNUSED;
  {
    xtensa_current_frame_size = 0;
  }
  
***************
*** 2326,2332 ****
    rtx result, retaddr;
  
    if (count == -1)
!     retaddr = gen_rtx_REG (Pmode, 0);
    else
      {
        rtx addr = plus_constant (frame, -4 * UNITS_PER_WORD);
--- 2314,2320 ----
    rtx result, retaddr;
  
    if (count == -1)
!     retaddr = gen_rtx_REG (Pmode, A0_REG);
    else
      {
        rtx addr = plus_constant (frame, -4 * UNITS_PER_WORD);
***************
*** 2882,2887 ****
--- 2870,2877 ----
  	}
        if (xtensa_simm12b (INTVAL (x)))
  	*total = 5;
+       else if (TARGET_CONST16)
+ 	*total = COSTS_N_INSNS (2);
        else
  	*total = 6;
        return true;
***************
*** 2889,2899 ****
      case CONST:
      case LABEL_REF:
      case SYMBOL_REF:
!       *total = 5;
        return true;
  
      case CONST_DOUBLE:
!       *total = 7;
        return true;
  
      case MEM:
--- 2879,2895 ----
      case CONST:
      case LABEL_REF:
      case SYMBOL_REF:
!       if (TARGET_CONST16)
! 	*total = COSTS_N_INSNS (2);
!       else
! 	*total = 5;
        return true;
  
      case CONST_DOUBLE:
!       if (TARGET_CONST16)
! 	*total = COSTS_N_INSNS (4);
!       else
! 	*total = 7;
        return true;
  
      case MEM:
Index: gcc/config/xtensa/xtensa.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/xtensa/xtensa.h,v
retrieving revision 1.31
diff -c -3 -r1.31 xtensa.h
*** gcc/config/xtensa/xtensa.h	14 May 2003 07:29:54 -0000	1.31
--- gcc/config/xtensa/xtensa.h	14 May 2003 18:14:16 -0000
***************
*** 61,66 ****
--- 61,67 ----
  #define MASK_HARD_FLOAT_RSQRT	0x00004000	/* floating-point recip sqrt */
  #define MASK_NO_FUSED_MADD	0x00008000	/* avoid f-p mul/add */
  #define MASK_SERIALIZE_VOLATILE 0x00010000	/* serialize volatile refs */
+ #define MASK_CONST16		0x00020000	/* use CONST16 instruction */
  
  /* Macros used in the machine description to test the flags.  */
  
***************
*** 81,92 ****
--- 82,95 ----
  #define TARGET_HARD_FLOAT_RSQRT	(target_flags & MASK_HARD_FLOAT_RSQRT)
  #define TARGET_NO_FUSED_MADD	(target_flags & MASK_NO_FUSED_MADD)
  #define TARGET_SERIALIZE_VOLATILE (target_flags & MASK_SERIALIZE_VOLATILE)
+ #define TARGET_CONST16		(target_flags & MASK_CONST16)
  
  /* Default target_flags if no switches are specified  */
  
  #define TARGET_DEFAULT (						\
    (XCHAL_HAVE_BE	? MASK_BIG_ENDIAN : 0) |			\
    (XCHAL_HAVE_DENSITY	? MASK_DENSITY : 0) |				\
+   (XCHAL_HAVE_L32R	? 0 : MASK_CONST16) |				\
    (XCHAL_HAVE_MAC16	? MASK_MAC16 : 0) |				\
    (XCHAL_HAVE_MUL16	? MASK_MUL16 : 0) |				\
    (XCHAL_HAVE_MUL32	? MASK_MUL32 : 0) |				\
***************
*** 114,119 ****
--- 117,126 ----
      N_("Use the Xtensa code density option")},				\
    {"no-density",		-MASK_DENSITY,				\
      N_("Do not use the Xtensa code density option")},			\
+   {"const16",			MASK_CONST16,				\
+     N_("Use CONST16 instruction to load constants")},			\
+   {"no-const16",		-MASK_CONST16,				\
+     N_("Use PC-relative L32R instruction to load constants")},		\
    {"mac16",			MASK_MAC16,				\
      N_("Use the Xtensa MAC16 option")},					\
    {"no-mac16",			-MASK_MAC16,				\
***************
*** 629,634 ****
--- 636,642 ----
     'A'	MAC16 accumulator (only if MAC16 option enabled)
     'B'	general-purpose registers (only if sext instruction enabled)
     'C'  general-purpose registers (only if mul16 option enabled)
+    'W'  general-purpose registers (only if const16 option enabled)
     'b'	coprocessor boolean registers
     'f'	floating-point registers
  */
***************
*** 699,705 ****
          && REGNO (OP) >= FIRST_PSEUDO_REGISTER)				\
     : ((CODE) == 'R') ? smalloffset_mem_p (OP)				\
     : ((CODE) == 'S') ? smalloffset_double_mem_p (OP)			\
!    : ((CODE) == 'T') ? constantpool_mem_p (OP)				\
     : ((CODE) == 'U') ? !constantpool_mem_p (OP)				\
     : FALSE)
  
--- 707,713 ----
          && REGNO (OP) >= FIRST_PSEUDO_REGISTER)				\
     : ((CODE) == 'R') ? smalloffset_mem_p (OP)				\
     : ((CODE) == 'S') ? smalloffset_double_mem_p (OP)			\
!    : ((CODE) == 'T') ? !TARGET_CONST16 && constantpool_mem_p (OP)	\
     : ((CODE) == 'U') ? !constantpool_mem_p (OP)				\
     : FALSE)
  
***************
*** 968,991 ****
      fprintf (STREAM, "\t.begin no-generics\n");				\
      fprintf (STREAM, "\tentry\tsp, %d\n", MIN_FRAME_SIZE);		\
  									\
!     /* GCC isn't prepared to deal with data at the beginning of the	\
!        trampoline, and the Xtensa l32r instruction requires that the	\
!        constant pool be located before the code.  We put the constant	\
!        pool in the middle of the trampoline and jump around it. */ 	\
  									\
!     fprintf (STREAM, "\tj\t.Lskipconsts\n");				\
      fprintf (STREAM, "\t.align\t4\n");					\
-     fprintf (STREAM, ".Lfnaddr:%s0\n", integer_asm_op (4, TRUE));	\
      fprintf (STREAM, ".Lchainval:%s0\n", integer_asm_op (4, TRUE));	\
      fprintf (STREAM, ".Lskipconsts:\n");				\
  									\
      /* store the static chain */					\
!     fprintf (STREAM, "\tl32r\ta8, .Lchainval\n");			\
!     fprintf (STREAM, "\ts32i\ta8, sp, %d\n",				\
! 	     MIN_FRAME_SIZE - (5 * UNITS_PER_WORD));			\
  									\
      /* set the proper stack pointer value */				\
!     fprintf (STREAM, "\tl32r\ta8, .Lfnaddr\n");				\
      fprintf (STREAM, "\tl32i\ta9, a8, 0\n");				\
      fprintf (STREAM, "\textui\ta9, a9, %d, 12\n",			\
  	     TARGET_BIG_ENDIAN ? 8 : 12);				\
--- 976,1002 ----
      fprintf (STREAM, "\t.begin no-generics\n");				\
      fprintf (STREAM, "\tentry\tsp, %d\n", MIN_FRAME_SIZE);		\
  									\
!     /* save the return address */					\
!     fprintf (STREAM, "\tmov\ta10, a0\n");				\
  									\
!     /* Use a CALL0 instruction to skip past the constants and in the	\
!        process get the PC into A0.  This allows PC-relative access to	\
!        the constants without relying on L32R, which may not always be	\
!        available.  */							\
! 									\
!     fprintf (STREAM, "\tcall0\t.Lskipconsts\n");			\
      fprintf (STREAM, "\t.align\t4\n");					\
      fprintf (STREAM, ".Lchainval:%s0\n", integer_asm_op (4, TRUE));	\
+     fprintf (STREAM, ".Lfnaddr:%s0\n", integer_asm_op (4, TRUE));	\
      fprintf (STREAM, ".Lskipconsts:\n");				\
  									\
      /* store the static chain */					\
!     fprintf (STREAM, "\taddi\ta0, a0, 3\n");				\
!     fprintf (STREAM, "\tl32i\ta8, a0, 0\n");				\
!     fprintf (STREAM, "\ts32i\ta8, sp, %d\n", MIN_FRAME_SIZE - 20);	\
  									\
      /* set the proper stack pointer value */				\
!     fprintf (STREAM, "\tl32i\ta8, a0, 4\n");				\
      fprintf (STREAM, "\tl32i\ta9, a8, 0\n");				\
      fprintf (STREAM, "\textui\ta9, a9, %d, 12\n",			\
  	     TARGET_BIG_ENDIAN ? 8 : 12);				\
***************
*** 994,999 ****
--- 1005,1013 ----
      fprintf (STREAM, "\tsub\ta9, sp, a9\n");				\
      fprintf (STREAM, "\tmovsp\tsp, a9\n");				\
  									\
+     /* restore the return address */					\
+     fprintf (STREAM, "\tmov\ta0, a10\n");				\
+ 									\
      /* jump to the instruction following the entry */			\
      fprintf (STREAM, "\taddi\ta8, a8, 3\n");				\
      fprintf (STREAM, "\tjx\ta8\n");					\
***************
*** 1001,1007 ****
    } while (0)
  
  /* Size in bytes of the trampoline, as an integer.  */
! #define TRAMPOLINE_SIZE 49
  
  /* Alignment required for trampolines, in bits.  */
  #define TRAMPOLINE_ALIGNMENT (32)
--- 1015,1021 ----
    } while (0)
  
  /* Size in bytes of the trampoline, as an integer.  */
! #define TRAMPOLINE_SIZE 59
  
  /* Alignment required for trampolines, in bits.  */
  #define TRAMPOLINE_ALIGNMENT (32)
***************
*** 1010,1017 ****
  #define INITIALIZE_TRAMPOLINE(ADDR, FUNC, CHAIN)			\
    do {									\
      rtx addr = ADDR;							\
-     emit_move_insn (gen_rtx_MEM (SImode, plus_constant (addr, 8)), FUNC); \
      emit_move_insn (gen_rtx_MEM (SImode, plus_constant (addr, 12)), CHAIN); \
      emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__xtensa_sync_caches"), \
  		       0, VOIDmode, 1, addr, Pmode);			\
    } while (0)
--- 1024,1031 ----
  #define INITIALIZE_TRAMPOLINE(ADDR, FUNC, CHAIN)			\
    do {									\
      rtx addr = ADDR;							\
      emit_move_insn (gen_rtx_MEM (SImode, plus_constant (addr, 12)), CHAIN); \
+     emit_move_insn (gen_rtx_MEM (SImode, plus_constant (addr, 16)), FUNC); \
      emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__xtensa_sync_caches"), \
  		       0, VOIDmode, 1, addr, Pmode);			\
    } while (0)
***************
*** 1128,1134 ****
  									\
      /* allow constant pool addresses */					\
      if ((MODE) != BLKmode && GET_MODE_SIZE (MODE) >= UNITS_PER_WORD	\
! 	&& constantpool_address_p (xinsn))				\
        goto LABEL;							\
  									\
      while (GET_CODE (xinsn) == SUBREG)					\
--- 1142,1148 ----
  									\
      /* allow constant pool addresses */					\
      if ((MODE) != BLKmode && GET_MODE_SIZE (MODE) >= UNITS_PER_WORD	\
! 	&& !TARGET_CONST16 && constantpool_address_p (xinsn))		\
        goto LABEL;							\
  									\
      while (GET_CODE (xinsn) == SUBREG)					\
***************
*** 1330,1336 ****
    {"call_insn_operand",		{ CONST_INT, CONST, SYMBOL_REF, REG }},	\
    {"move_operand",		{ REG, SUBREG, MEM, CONST_INT, CONST_DOUBLE, \
  				  CONST, SYMBOL_REF, LABEL_REF }},	\
-   {"non_const_move_operand",	{ REG, SUBREG, MEM }},			\
    {"const_float_1_operand",	{ CONST_DOUBLE }},			\
    {"branch_operator",		{ EQ, NE, LT, GE }},			\
    {"ubranch_operator",		{ LTU, GEU }},				\
--- 1344,1349 ----
Index: gcc/config/xtensa/xtensa.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/xtensa/xtensa.md,v
retrieving revision 1.10
diff -c -3 -r1.10 xtensa.md
*** gcc/config/xtensa/xtensa.md	17 Apr 2003 11:24:04 -0000	1.10
--- gcc/config/xtensa/xtensa.md	14 May 2003 18:14:16 -0000
***************
*** 29,41 ****
--- 29,44 ----
  
  (define_constants [
    (A0_REG		0)
+   (A1_REG		1)
    (A7_REG		7)
+   (A8_REG		8)
  
    (UNSPEC_NSAU		1)
    (UNSPEC_NOP		2)
    (UNSPEC_PLT		3)
    (UNSPEC_RET_ADDR	4)
    (UNSPECV_SET_FP	1)
+   (UNSPECV_ENTRY	2)
  ])
  
  ;;
***************
*** 919,939 ****
    ""
    "
  {
!   if (CONSTANT_P (operands[1]))
      {
        rtx src0, src1, dst0, dst1;
!       if ((dst0 = operand_subword (operands[0], 0, 1, DImode))
! 	  && (src0 = operand_subword (operands[1], 0, 1, DImode))
! 	  && (dst1 = operand_subword (operands[0], 1, 1, DImode))
! 	  && (src1 = operand_subword (operands[1], 1, 1, DImode)))
! 	{
! 	  emit_insn (gen_movsi (dst0, src0));
! 	  emit_insn (gen_movsi (dst1, src1));
! 	  DONE;
! 	}
!       else
! 	/* any other constant will be loaded from memory */
! 	operands[1] = force_const_mem (DImode, operands[1]);
      }
  
    if (!(reload_in_progress | reload_completed))
--- 922,940 ----
    ""
    "
  {
!   if (CONSTANT_P (operands[1])
!       && register_operand (operands[0], DImode))
      {
        rtx src0, src1, dst0, dst1;
!       dst0 = operand_subword (operands[0], 0, 1, DImode);
!       src0 = operand_subword (operands[1], 0, 1, DImode);
!       dst1 = operand_subword (operands[0], 1, 1, DImode);
!       src1 = operand_subword (operands[1], 1, 1, DImode);
!       if (!dst0 || !src0 || !dst1 || !src1)
!         abort ();
!       emit_insn (gen_movsi (dst0, src0));
!       emit_insn (gen_movsi (dst1, src1));
!       DONE;
      }
  
    if (!(reload_in_progress | reload_completed))
***************
*** 948,1007 ****
  }")
  
  (define_insn "movdi_internal"
!   [(set (match_operand:DI 0 "nonimmed_operand" "=D,D,S,a,a,a,U")
! 	(match_operand:DI 1 "non_const_move_operand" "d,S,d,r,T,U,r"))]
    "register_operand (operands[0], DImode)
     || register_operand (operands[1], DImode)"
    "*
  {
    switch (which_alternative)
      {
      case 0: return \"mov.n\\t%0, %1\;mov.n\\t%D0, %D1\";
      case 2: return \"%v0s32i.n\\t%1, %0\;s32i.n\\t%D1, %N0\";
      case 3: return \"mov\\t%0, %1\;mov\\t%D0, %D1\";
!     case 6: return \"%v0s32i\\t%1, %0\;s32i\\t%D1, %N0\";
  
      case 1:
      case 4:
!     case 5:
!       {
! 	/* Check if the first half of the destination register is used
! 	   in the source address.  If so, reverse the order of the loads
! 	   so that the source address doesn't get clobbered until it is
! 	   no longer needed. */
! 
! 	rtx dstreg = operands[0];
! 	if (GET_CODE (dstreg) == SUBREG)
! 	  dstreg = SUBREG_REG (dstreg);
! 	if (GET_CODE (dstreg) != REG)
! 	  abort();
! 
! 	if (reg_mentioned_p (dstreg, operands[1]))
! 	  {
! 	    switch (which_alternative)
! 	      {
! 	      case 1: return \"%v1l32i.n\\t%D0, %N1\;l32i.n\\t%0, %1\";
! 	      case 4: return \"%v1l32r\\t%D0, %N1\;l32r\\t%0, %1\";
! 	      case 5: return \"%v1l32i\\t%D0, %N1\;l32i\\t%0, %1\";
! 	      }
! 	  }
! 	else
! 	  {
! 	    switch (which_alternative)
! 	      {
! 	      case 1: return \"%v1l32i.n\\t%0, %1\;l32i.n\\t%D0, %N1\";
! 	      case 4: return \"%v1l32r\\t%0, %1\;l32r\\t%D0, %N1\";
! 	      case 5: return \"%v1l32i\\t%0, %1\;l32i\\t%D0, %N1\";
! 	      }
! 	  }
!       }
      }
    abort ();
    return \"\";
  }"
!   [(set_attr "type"	"move,load,store,move,load,load,store")
     (set_attr "mode"	"DI")
!    (set_attr "length"	"4,4,4,6,6,6,6")])
  
  
  ;; 32-bit Integer moves
--- 949,1004 ----
  }")
  
  (define_insn "movdi_internal"
!   [(set (match_operand:DI 0 "nonimmed_operand" "=D,D,S,a,a,U")
! 	(match_operand:DI 1 "nonimmed_operand" "d,S,d,r,U,r"))]
    "register_operand (operands[0], DImode)
     || register_operand (operands[1], DImode)"
    "*
  {
+   rtx dstreg;
    switch (which_alternative)
      {
      case 0: return \"mov.n\\t%0, %1\;mov.n\\t%D0, %D1\";
      case 2: return \"%v0s32i.n\\t%1, %0\;s32i.n\\t%D1, %N0\";
      case 3: return \"mov\\t%0, %1\;mov\\t%D0, %D1\";
!     case 5: return \"%v0s32i\\t%1, %0\;s32i\\t%D1, %N0\";
  
      case 1:
      case 4:
!       /* Check if the first half of the destination register is used
! 	 in the source address.  If so, reverse the order of the loads
! 	 so that the source address doesn't get clobbered until it is
! 	 no longer needed. */
! 
!       dstreg = operands[0];
!       if (GET_CODE (dstreg) == SUBREG)
! 	dstreg = SUBREG_REG (dstreg);
!       if (GET_CODE (dstreg) != REG)
! 	abort();
! 
!       if (reg_mentioned_p (dstreg, operands[1]))
! 	{
! 	  switch (which_alternative)
! 	    {
! 	    case 1: return \"%v1l32i.n\\t%D0, %N1\;l32i.n\\t%0, %1\";
! 	    case 4: return \"%v1l32i\\t%D0, %N1\;l32i\\t%0, %1\";
! 	    }
! 	}
!       else
! 	{
! 	  switch (which_alternative)
! 	    {
! 	    case 1: return \"%v1l32i.n\\t%0, %1\;l32i.n\\t%D0, %N1\";
! 	    case 4: return \"%v1l32i\\t%0, %1\;l32i\\t%D0, %N1\";
! 	    }
! 	}
      }
    abort ();
    return \"\";
  }"
!   [(set_attr "type"	"move,load,store,move,load,store")
     (set_attr "mode"	"DI")
!    (set_attr "length"	"4,4,4,6,6,6")])
  
  
  ;; 32-bit Integer moves
***************
*** 1017,1024 ****
  }")
  
  (define_insn "movsi_internal"
!   [(set (match_operand:SI 0 "nonimmed_operand" "=D,D,D,D,R,R,a,q,a,a,a,U,*a,*A")
! 	(match_operand:SI 1 "move_operand" "M,D,d,R,D,d,r,r,I,T,U,r,*A,*r"))]
    "xtensa_valid_move (SImode, operands)"
    "@
     movi.n\\t%0, %x1
--- 1014,1021 ----
  }")
  
  (define_insn "movsi_internal"
!   [(set (match_operand:SI 0 "nonimmed_operand" "=D,D,D,D,R,R,a,q,a,W,a,a,U,*a,*A")
! 	(match_operand:SI 1 "move_operand" "M,D,d,R,D,d,r,r,I,i,T,U,r,*A,*r"))]
    "xtensa_valid_move (SImode, operands)"
    "@
     movi.n\\t%0, %x1
***************
*** 1030,1043 ****
     mov\\t%0, %1
     movsp\\t%0, %1
     movi\\t%0, %x1
     %v1l32r\\t%0, %1
     %v1l32i\\t%0, %1
     %v0s32i\\t%1, %0
     rsr\\t%0, 16 # ACCLO
     wsr\\t%1, 16 # ACCLO"
!   [(set_attr "type"	"move,move,move,load,store,store,move,move,move,load,load,store,rsr,wsr")
     (set_attr "mode"	"SI")
!    (set_attr "length"	"2,2,2,2,2,2,3,3,3,3,3,3,3,3")])
  
  ;; 16-bit Integer moves
  
--- 1027,1041 ----
     mov\\t%0, %1
     movsp\\t%0, %1
     movi\\t%0, %x1
+    const16\\t%0, %t1\;const16\\t%0, %b1
     %v1l32r\\t%0, %1
     %v1l32i\\t%0, %1
     %v0s32i\\t%1, %0
     rsr\\t%0, 16 # ACCLO
     wsr\\t%1, 16 # ACCLO"
!   [(set_attr "type" "move,move,move,load,store,store,move,move,move,move,load,load,store,rsr,wsr")
     (set_attr "mode"	"SI")
!    (set_attr "length"	"2,2,2,2,2,2,3,3,3,6,3,3,3,3,3")])
  
  ;; 16-bit Integer moves
  
***************
*** 1105,1119 ****
    ""
    "
  {
!   if (GET_CODE (operands[1]) == CONST_DOUBLE)
      operands[1] = force_const_mem (SFmode, operands[1]);
  
    if (!(reload_in_progress | reload_completed))
      {
!       if (((!register_operand (operands[0], SFmode)
  	   && !register_operand (operands[1], SFmode))
  	  || (FP_REG_P (xt_true_regnum (operands[0]))
! 	      && constantpool_mem_p (operands[1]))))
  	operands[1] = force_reg (SFmode, operands[1]);
  
        if (xtensa_copy_incoming_a7 (operands, SFmode))
--- 1103,1118 ----
    ""
    "
  {
!   if (!TARGET_CONST16 && CONSTANT_P (operands[1]))
      operands[1] = force_const_mem (SFmode, operands[1]);
  
    if (!(reload_in_progress | reload_completed))
      {
!       if ((!register_operand (operands[0], SFmode)
  	   && !register_operand (operands[1], SFmode))
  	  || (FP_REG_P (xt_true_regnum (operands[0]))
! 	      && (constantpool_mem_p (operands[1])
! 	          || CONSTANT_P (operands[1]))))
  	operands[1] = force_reg (SFmode, operands[1]);
  
        if (xtensa_copy_incoming_a7 (operands, SFmode))
***************
*** 1122,1135 ****
  }")
  
  (define_insn "movsf_internal"
!   [(set (match_operand:SF 0 "nonimmed_operand"
! 			    "=f,f,U,D,D,R,a,f,a,a,a,U")
! 	(match_operand:SF 1 "non_const_move_operand"
! 			    "f,U,f,d,R,d,r,r,f,T,U,r"))]
    "((register_operand (operands[0], SFmode)
       || register_operand (operands[1], SFmode))
!     && (!FP_REG_P (xt_true_regnum (operands[0]))
!         || !constantpool_mem_p (operands[1])))"
    "@
     mov.s\\t%0, %1
     %v1lsi\\t%0, %1
--- 1121,1132 ----
  }")
  
  (define_insn "movsf_internal"
!   [(set (match_operand:SF 0 "nonimmed_operand" "=f,f,U,D,D,R,a,f,a,W,a,a,U")
! 	(match_operand:SF 1 "move_operand" "f,U,f,d,R,d,r,r,f,F,T,U,r"))]
    "((register_operand (operands[0], SFmode)
       || register_operand (operands[1], SFmode))
!     && !(FP_REG_P (xt_true_regnum (operands[0]))
!          && (constantpool_mem_p (operands[1]) || CONSTANT_P (operands[1]))))"
    "@
     mov.s\\t%0, %1
     %v1lsi\\t%0, %1
***************
*** 1140,1151 ****
     mov\\t%0, %1
     wfr\\t%0, %1
     rfr\\t%0, %1
     %v1l32r\\t%0, %1
     %v1l32i\\t%0, %1
     %v0s32i\\t%1, %0"
!   [(set_attr "type"	"farith,fload,fstore,move,load,store,move,farith,farith,load,load,store")
     (set_attr "mode"	"SF")
!    (set_attr "length"	"3,3,3,2,2,2,3,3,3,3,3,3")])
  
  (define_insn "*lsiu"
    [(set (match_operand:SF 0 "register_operand" "=f")
--- 1137,1149 ----
     mov\\t%0, %1
     wfr\\t%0, %1
     rfr\\t%0, %1
+    const16\\t%0, %t1\;const16\\t%0, %b1
     %v1l32r\\t%0, %1
     %v1l32i\\t%0, %1
     %v0s32i\\t%1, %0"
!   [(set_attr "type"	"farith,fload,fstore,move,load,store,move,farith,farith,move,load,load,store")
     (set_attr "mode"	"SF")
!    (set_attr "length"	"3,3,3,2,2,2,3,3,3,6,3,3,3")])
  
  (define_insn "*lsiu"
    [(set (match_operand:SF 0 "register_operand" "=f")
***************
*** 1189,1196 ****
    ""
    "
  {
!   if (GET_CODE (operands[1]) == CONST_DOUBLE)
!     operands[1] = force_const_mem (DFmode, operands[1]);
  
    if (!(reload_in_progress | reload_completed))
      {
--- 1187,1205 ----
    ""
    "
  {
!   if (CONSTANT_P (operands[1]))
!     {
!       rtx src0, src1, dst0, dst1;
!       dst0 = operand_subword (operands[0], 0, 1, DFmode);
!       src0 = operand_subword (operands[1], 0, 1, DFmode);
!       dst1 = operand_subword (operands[0], 1, 1, DFmode);
!       src1 = operand_subword (operands[1], 1, 1, DFmode);
!       if (!dst0 || !src0 || !dst1 || !src1)
!         abort ();
!       emit_insn (gen_movsi (dst0, src0));
!       emit_insn (gen_movsi (dst1, src1));
!       DONE;
!     }
  
    if (!(reload_in_progress | reload_completed))
      {
***************
*** 1204,1263 ****
  }")
  
  (define_insn "movdf_internal"
!   [(set (match_operand:DF 0 "nonimmed_operand" "=D,D,S,a,a,a,U")
! 	(match_operand:DF 1 "non_const_move_operand" "d,S,d,r,T,U,r"))]
    "register_operand (operands[0], DFmode)
     || register_operand (operands[1], DFmode)"
    "*
  {
    switch (which_alternative)
      {
      case 0: return \"mov.n\\t%0, %1\;mov.n\\t%D0, %D1\";
      case 2: return \"%v0s32i.n\\t%1, %0\;s32i.n\\t%D1, %N0\";
      case 3: return \"mov\\t%0, %1\;mov\\t%D0, %D1\";
!     case 6: return \"%v0s32i\\t%1, %0\;s32i\\t%D1, %N0\";
  
      case 1:
      case 4:
!     case 5:
!       {
! 	/* Check if the first half of the destination register is used
! 	   in the source address.  If so, reverse the order of the loads
! 	   so that the source address doesn't get clobbered until it is
! 	   no longer needed. */
! 
! 	rtx dstreg = operands[0];
! 	if (GET_CODE (dstreg) == SUBREG)
! 	  dstreg = SUBREG_REG (dstreg);
! 	if (GET_CODE (dstreg) != REG)
! 	  abort ();
! 
! 	if (reg_mentioned_p (dstreg, operands[1]))
! 	  {
! 	    switch (which_alternative)
! 	      {
! 	      case 1: return \"%v1l32i.n\\t%D0, %N1\;l32i.n\\t%0, %1\";
! 	      case 4: return \"%v1l32r\\t%D0, %N1\;l32r\\t%0, %1\";
! 	      case 5: return \"%v1l32i\\t%D0, %N1\;l32i\\t%0, %1\";
! 	      }
! 	  }
! 	else
! 	  {
! 	    switch (which_alternative)
! 	      {
! 	      case 1: return \"%v1l32i.n\\t%0, %1\;l32i.n\\t%D0, %N1\";
! 	      case 4: return \"%v1l32r\\t%0, %1\;l32r\\t%D0, %N1\";
! 	      case 5: return \"%v1l32i\\t%0, %1\;l32i\\t%D0, %N1\";
! 	      }
! 	  }
!       }
      }
    abort ();
    return \"\";
  }"
!   [(set_attr "type"	"move,load,store,move,load,load,store")
     (set_attr "mode"	"DF")
!    (set_attr "length"	"4,4,4,6,6,6,6")])
  
  ;; Block moves
  
--- 1213,1268 ----
  }")
  
  (define_insn "movdf_internal"
!   [(set (match_operand:DF 0 "nonimmed_operand" "=D,D,S,a,a,U")
! 	(match_operand:DF 1 "nonimmed_operand" "d,S,d,r,U,r"))]
    "register_operand (operands[0], DFmode)
     || register_operand (operands[1], DFmode)"
    "*
  {
+   rtx dstreg;
    switch (which_alternative)
      {
      case 0: return \"mov.n\\t%0, %1\;mov.n\\t%D0, %D1\";
      case 2: return \"%v0s32i.n\\t%1, %0\;s32i.n\\t%D1, %N0\";
      case 3: return \"mov\\t%0, %1\;mov\\t%D0, %D1\";
!     case 5: return \"%v0s32i\\t%1, %0\;s32i\\t%D1, %N0\";
  
      case 1:
      case 4:
!       /* Check if the first half of the destination register is used
! 	 in the source address.  If so, reverse the order of the loads
! 	 so that the source address doesn't get clobbered until it is
! 	 no longer needed.  */
! 
!       dstreg = operands[0];
!       if (GET_CODE (dstreg) == SUBREG)
! 	dstreg = SUBREG_REG (dstreg);
!       if (GET_CODE (dstreg) != REG)
! 	abort ();
! 
!       if (reg_mentioned_p (dstreg, operands[1]))
! 	{
! 	  switch (which_alternative)
! 	    {
! 	    case 1: return \"%v1l32i.n\\t%D0, %N1\;l32i.n\\t%0, %1\";
! 	    case 4: return \"%v1l32i\\t%D0, %N1\;l32i\\t%0, %1\";
! 	    }
! 	}
!       else
! 	{
! 	  switch (which_alternative)
! 	    {
! 	    case 1: return \"%v1l32i.n\\t%0, %1\;l32i.n\\t%D0, %N1\";
! 	    case 4: return \"%v1l32i\\t%0, %1\;l32i\\t%D0, %N1\";
! 	    }
! 	}
      }
    abort ();
    return \"\";
  }"
!   [(set_attr "type"	"move,load,store,move,load,store")
     (set_attr "mode"	"DF")
!    (set_attr "length"	"4,4,4,6,6,6")])
  
  ;; Block moves
  
***************
*** 2340,2345 ****
--- 2345,2368 ----
     (set_attr "mode"	"none")
     (set_attr "length"	"3")])
  
+ (define_insn "entry"
+   [(set (reg:SI A1_REG)
+ 	(unspec_volatile:SI [(match_operand:SI 0 "const_int_operand" "i")
+ 			     (match_operand:SI 1 "const_int_operand" "i")]
+ 			    UNSPECV_ENTRY))]
+   ""
+   "*
+ {
+   if (frame_pointer_needed)
+     output_asm_insn (\".frame\\ta7, %0\", operands);
+   else
+     output_asm_insn (\".frame\\tsp, %0\", operands);
+   return \"entry\\tsp, %1\";
+ }"
+   [(set_attr "type"	"move")
+    (set_attr "mode"	"SI")
+    (set_attr "length"	"3")])
+ 
  (define_insn "return"
    [(return)
     (use (reg:SI A0_REG))]
***************
*** 2361,2366 ****
--- 2384,2407 ----
  ;;  ....................
  ;;
  
+ (define_expand "prologue"
+   [(const_int 0)]
+   ""
+   "
+ {
+   xtensa_expand_prologue ();
+   DONE;
+ }")
+ 
+ (define_expand "epilogue"
+   [(return)]
+   ""
+   "
+ {
+   emit_jump_insn (gen_return ());
+   DONE;
+ }")
+ 
  (define_insn "nop"
    [(const_int 0)]
    ""
***************
*** 2400,2406 ****
  ;; to set up the frame pointer.
  
  (define_insn "set_frame_ptr"
!   [(set (reg:SI A7_REG) (unspec_volatile [(const_int 0)] UNSPECV_SET_FP))]
    ""
    "*
  {
--- 2441,2447 ----
  ;; to set up the frame pointer.
  
  (define_insn "set_frame_ptr"
!   [(set (reg:SI A7_REG) (unspec_volatile:SI [(const_int 0)] UNSPECV_SET_FP))]
    ""
    "*
  {
***************
*** 2414,2420 ****
  
  ;; Post-reload splitter to remove fp assignment when it's not needed.
  (define_split
!   [(set (reg:SI A7_REG) (unspec_volatile [(const_int 0)] UNSPECV_SET_FP))]
    "reload_completed && !frame_pointer_needed"
    [(unspec [(const_int 0)] UNSPEC_NOP)]
    "")
--- 2455,2461 ----
  
  ;; Post-reload splitter to remove fp assignment when it's not needed.
  (define_split
!   [(set (reg:SI A7_REG) (unspec_volatile:SI [(const_int 0)] UNSPECV_SET_FP))]
    "reload_completed && !frame_pointer_needed"
    [(unspec [(const_int 0)] UNSPEC_NOP)]
    "")
Index: gcc/doc/invoke.texi
===================================================================
RCS file: /cvs/gcc/gcc/gcc/doc/invoke.texi,v
retrieving revision 1.275
diff -c -3 -r1.275 invoke.texi
*** gcc/doc/invoke.texi	14 May 2003 02:22:12 -0000	1.275
--- gcc/doc/invoke.texi	14 May 2003 18:14:17 -0000
***************
*** 632,637 ****
--- 632,638 ----
  @emph{Xtensa Options}
  @gccoptlist{-mbig-endian  -mlittle-endian @gol
  -mdensity  -mno-density @gol
+ -mconst16 -mno-const16 @gol
  -mmac16  -mno-mac16 @gol
  -mmul16  -mno-mul16 @gol
  -mmul32  -mno-mul32 @gol
***************
*** 10648,10653 ****
--- 10649,10664 ----
  @opindex mdensity
  @opindex mno-density
  Enable or disable use of the optional Xtensa code density instructions.
+ 
+ @item -mconst16
+ @itemx -mno-const16
+ @opindex mconst16
+ @opindex mno-const16
+ Enable or disable use of CONST16 instructions for loading constant values.
+ The CONST16 instruction is currently not a standard option from Tensilica.
+ When enabled, CONST16 instructions are always used in place of the standard
+ L32R instructions.  The use of CONST16 is enabled by default only if the
+ L32R instruction is not available.
  
  @item -mmac16
  @itemx -mno-mac16

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]