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]

[nios2] [4/7] Support new R2 instructions


This patch adds GCC support for the bulk of the new R2 instructions --
everything except the new CDX load/store multiple instructions (part
5) and the instructions that are only emitted by new builtins (part
7).

CDX adds a group of 16-bit instructions similar to existing 32-bit
instructions, but with restrictions on which registers can be used,
smaller constant ranges, and the like to achieve the compression.
These instructions have an explicit ".n" suffix in the assembly
language syntax, rather than the encoding being selected automatically
by the assembler.  Instead of adding new insns with a "TARGET_HAS_CDX"
condition, or using the "enabled" attribute to control new
alternatives to the existing insn patterns, Chung-Lin came up with the
clever idea of moving the decision-making to the computation of the
"length" attribute in nios2_cdx_narrow_form_p.  Then
nios2_print_operand maps "%." onto ".n" or not depending on the
length.

Committed as 225796.

-Sandra

2015-07-14  Sandra Loosemore  <sandra@codesourcery.com>
	    Cesar Philippidis  <cesar@codesourcery.com>
	    Chung-Lin Tang  <cltang@codesourcery.com>

	gcc/
	* config/nios2/nios2.h (LABEL_ALIGN): Define.
	(REG_ALLOC_ORDER): Define.
	(ADJUST_REG_ALLOC_ORDER): Define.
	(HONOR_REG_ALLOC_ORDER): Define.
	(CDX_REG_P): Define.
	(ANDCLEAR_INT): Define.
	* config/nios2/nios2-protos.h (nios2_add_insn_asm): Declare.
	(nios2_label_align): Declare.
	(nios2_cdx_narrow_form_p): Declare.
	(nios2_adjust_reg_alloc_order): Declare.
	* config/nios2/nios2.c (nios2_rtx_costs): Adjust for BMX zero-extract
	operation.
	(nios2_large_unspec_reloc_p): New function, split from...
	(nios2_legitimate_pic_operand_p): ...here.
	(nios2_emit_move_sequence): Add *high/*lo_sum constant expand code.
	(nios2_print_operand_punct_valid_p): New.
	(nios2_print_operand): Add %., %!, %x, %y, %A.  Remove %U.
	(split_mem_address): New.
	(split_alu_insn): New.
	(cdxreg): New.
	(cdx_add_immed, cdx_and_immed, cdx_mov_immed, cdx_shift_immed): New.
	(enum nios2_add_insn_kind): New.
	(nios2_add_insn_names, nios2_add_insn_narrow): New.
	(nios2_add_insn_classify): New.
	(nios2_add_insn_asm): New.
	(nios2_cdx_narrow_form_p): New.
	(label_align, min_labelno, max_labelno): New.
	(nios2_reorg): New.
	(nios2_label_align): New.
	(nios2_adjust_reg_alloc_order): New.
	(TARGET_PRINT_OPERAND_PUNCT_VALID_P): Define.
	(TARGET_MACHINE_DEPENDENT_REORG): Define.
	* config/nios2/constraints.md (P): New constraint.
	* config/nios2/predicates.md (const_and_operand): New.
	(and_operand): New.
	(stack_memory_operand): New.
	* config/nios2/nios2.md (SP_REGNO): Define stack pointer regno.
	(length): Update to use nios2_cdx_narrow_form_p().
	(type): Add new insn type values.
	(control, alu, st, ld, shift): Update insn reservations with
	new insn type values.
	(*high, *lo_sum): Define new insn patterns for constant generation.
	(movqi_internal, movhi_internal, movsi_internal): Reduce
	alternatives, update asm template to handle CDX variants, update
	type attributes.
	(zero_extendhisi2, zero_extendqi<mode>2): Add CDX variants to asm
	template, update type attributes.
	(extendhisi2, extendqi<mode>2): Likewise.
	(addsi3): Change to use function for asm string.
	(subsi3): Add CDX notation to asm template, update type attributes.
	(negsi3, one_cmplsi3): Likewise.
	(andsi3): New pattern, specialized from logical patterns.
	(<code>si3): Remove and case, combine alternatives, update asm
	template.
	(<shift_op>si3): Add CDX notation, update type attributes.
	(rotrsi3): Update type attribute.
	(*merge, extzv, insv): New insn patterns.
	(return): Change to define_expand.
	(simple_return): Add CDX notation, update type attributes.
	(indirect_jump): Add CDX notation.
	(jump): Update asm cases, update length attribute expression.
	(*call, *call_value, *sibcall, *sibcall_value): Add CDX variant.
	(nios2_cbranch): Update asm cases and length attribute expression
	to handle CDX variants.
	(nios2_cmp<code>): Update asm template.
	(nop): Add CDX notation, update type attributes.
	(trap): Add CDX notation.
	(ctrapsi4): Update asm cases and length attribute expression to
	handle CDX variant.
	* doc/md.texi (Machine Constraints): Document P constraint.

	gcc/testsuite/
	* gcc.target/nios2/andci.c: New.
	* gcc.target/nios2/bmx.c: New.
	* gcc.target/nios2/cdx-add.c: New.
	* gcc.target/nios2/cdx-branch.c: New.
	* gcc.target/nios2/cdx-callret.c: New.
	* gcc.target/nios2/cdx-loadstore.c: New.
	* gcc.target/nios2/cdx-logical.c: New.
	* gcc.target/nios2/cdx-mov.c: New.
	* gcc.target/nios2/cdx-shift.c: New.
	* gcc.target/nios2/cdx-sub.c: New.
	* gcc.target/nios2/nios2-trap-insn.c: Adjust pattern.
Index: gcc/config/nios2/nios2.h
===================================================================
--- gcc/config/nios2/nios2.h	(revision 225793)
+++ gcc/config/nios2/nios2.h	(working copy)
@@ -96,6 +96,8 @@
   ((TREE_CODE (EXP) == STRING_CST)                              \
    && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN))
 
+#define LABEL_ALIGN(LABEL) nios2_label_align (LABEL)
+
 /* Layout of source language data types.  */
 
 #define INT_TYPE_SIZE 32
@@ -175,6 +177,20 @@
 #define HARD_REGNO_NREGS(REGNO, MODE)            \
   ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
 
+/* Order in which to allocate registers.  Each register must be
+   listed once.  This is the default ordering for R1 and non-CDX R2
+   code.  For CDX, we overwrite this in ADJUST_REG_ALLOC_ORDER.  */
+#define REG_ALLOC_ORDER							\
+  { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, \
+      20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, \
+      37, 38, 39 }
+
+#define ADJUST_REG_ALLOC_ORDER nios2_adjust_reg_alloc_order ()
+
+/* Caller-save costs can be less emphasized under R2 CDX, where we can
+   use push.n/pop.n.  */
+#define HONOR_REG_ALLOC_ORDER (TARGET_HAS_CDX)
+
 /* Register Classes.  */
 
 enum reg_class
@@ -213,6 +229,9 @@ enum reg_class
 #define CLASS_MAX_NREGS(CLASS, MODE)					\
   ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
 
+#define CDX_REG_P(REGNO)						\
+  ((REGNO) == 16 || (REGNO) == 17 || (2 <= (REGNO) && (REGNO) <= 7))
+
 /* Tests for various kinds of constants used in the Nios II port.  */
 
 #define SMALL_INT(X) ((unsigned HOST_WIDE_INT)(X) + 0x8000 < 0x10000)
@@ -222,6 +241,8 @@ enum reg_class
 #define SHIFT_INT(X) ((X) >= 0 && (X) <= 31)
 #define RDWRCTL_INT(X) ((X) >= 0 && (X) <= 31)
 #define CUSTOM_INSN_OPCODE(X) ((X) >= 0 && (X) <= 255)
+#define ANDCLEAR_INT(X) \
+  (((X) & 0xffff) == 0xffff || (((X) >> 16) & 0xffff) == 0xffff)
 
 /* Say that the epilogue uses the return address register.  Note that
    in the case of sibcalls, the values "used by the epilogue" are
Index: gcc/config/nios2/nios2-protos.h
===================================================================
--- gcc/config/nios2/nios2-protos.h	(revision 225793)
+++ gcc/config/nios2/nios2-protos.h	(working copy)
@@ -42,12 +42,18 @@ extern bool nios2_validate_fpu_compare (
 
 extern bool nios2_fpu_insn_enabled (enum n2fpu_code);
 extern const char * nios2_fpu_insn_asm (enum n2fpu_code);
+extern const char * nios2_add_insn_asm (rtx_insn *, rtx *);
 
 extern bool nios2_legitimate_pic_operand_p (rtx);
 extern bool gprel_constant_p (rtx);
 extern bool nios2_regno_ok_for_base_p (int, bool);
 extern bool nios2_unspec_reloc_p (rtx);
 
+extern int nios2_label_align (rtx);
+extern bool nios2_cdx_narrow_form_p (rtx_insn *);
+
+extern void nios2_adjust_reg_alloc_order (void);
+
 #ifdef TREE_CODE
 #ifdef ARGS_SIZE_RTX
 /* expr.h defines both ARGS_SIZE_RTX and `enum direction' */
Index: gcc/config/nios2/nios2.c
===================================================================
--- gcc/config/nios2/nios2.c	(revision 225793)
+++ gcc/config/nios2/nios2.c	(working copy)
@@ -1195,6 +1195,13 @@ nios2_rtx_costs (rtx x, machine_mode mod
           return false;
         }
 
+    case ZERO_EXTRACT:
+      if (TARGET_HAS_BMX)
+	{
+          *total = COSTS_N_INSNS (1);
+          return true;
+	}
+
       default:
         return false;
     }
@@ -1262,6 +1269,14 @@ nios2_unspec_reloc_p (rtx op)
 	  && ! nios2_large_offset_p (XINT (XEXP (op, 0), 1)));
 }
 
+static bool
+nios2_large_unspec_reloc_p (rtx op)
+{
+  return (GET_CODE (op) == CONST
+	  && GET_CODE (XEXP (op, 0)) == UNSPEC
+	  && nios2_large_offset_p (XINT (XEXP (op, 0), 1)));
+}
+
 /* Helper to generate unspec constant.  */
 static rtx
 nios2_unspec_offset (rtx loc, int unspec)
@@ -1871,9 +1886,7 @@ nios2_load_pic_address (rtx sym, int uns
 bool
 nios2_legitimate_pic_operand_p (rtx x)
 {
-  if (GET_CODE (x) == CONST
-      && GET_CODE (XEXP (x, 0)) == UNSPEC
-      && nios2_large_offset_p (XINT (XEXP (x, 0), 1)))
+  if (nios2_large_unspec_reloc_p (x))
     return true;
 
   return ! (GET_CODE (x) == SYMBOL_REF
@@ -2001,10 +2014,37 @@ nios2_emit_move_sequence (rtx *operands,
       from = copy_to_mode_reg (mode, from);
     }
 
-  if (GET_CODE (from) == SYMBOL_REF || GET_CODE (from) == LABEL_REF
-      || (GET_CODE (from) == CONST
-	  && GET_CODE (XEXP (from, 0)) != UNSPEC))
-    from = nios2_legitimize_constant_address (from);
+  if (CONSTANT_P (from))
+    {
+      if (CONST_INT_P (from))
+	{
+	  if (!SMALL_INT (INTVAL (from))
+	      && !SMALL_INT_UNSIGNED (INTVAL (from))
+	      && !UPPER16_INT (INTVAL (from)))
+	    {
+	      HOST_WIDE_INT high = (INTVAL (from) + 0x8000) & ~0xffff;
+	      HOST_WIDE_INT low = INTVAL (from) & 0xffff;
+	      emit_move_insn (to, gen_int_mode (high, SImode));
+	      emit_insn (gen_add2_insn (to, gen_int_mode (low, HImode)));
+	      set_unique_reg_note (get_last_insn (), REG_EQUAL,
+				   copy_rtx (from));
+	      return true;
+	    }
+	}
+      else if (!gprel_constant_p (from))
+	{
+	  if (!nios2_large_unspec_reloc_p (from))
+	    from = nios2_legitimize_constant_address (from);
+	  if (CONSTANT_P (from))
+	    {
+	      emit_insn (gen_rtx_SET (to, gen_rtx_HIGH (Pmode, from)));
+	      emit_insn (gen_rtx_SET (to, gen_rtx_LO_SUM (Pmode, to, from)));
+	      set_unique_reg_note (get_last_insn (), REG_EQUAL,
+				   copy_rtx (operands[1]));
+	      return true;
+	    }
+	}
+    }
 
   operands[0] = to;
   operands[1] = from;
@@ -2037,25 +2077,106 @@ nios2_adjust_call_address (rtx *call_op,
 
 /* Output assembly language related definitions.  */
 
+/* Implement TARGET_PRINT_OPERAND_PUNCT_VALID_P.  */
+static bool
+nios2_print_operand_punct_valid_p (unsigned char code)
+{
+  return (code == '.' || code == '!');
+}
+
+
 /* Print the operand OP to file stream FILE modified by LETTER.
    LETTER can be one of:
 
-     i: print "i" if OP is an immediate, except 0
-     o: print "io" if OP is volatile
-     z: for const0_rtx print $0 instead of 0
+     i: print i/hi/ui suffixes (used for mov instruction variants),
+        when OP is the appropriate immediate operand.
+
+     u: like 'i', except without "ui" suffix case (used for cmpgeu/cmpltu)
+
+     o: print "io" if OP needs volatile access (due to TARGET_BYPASS_CACHE
+        or TARGET_BYPASS_CACHE_VOLATILE).
+
+     x: print i/hi/ci/chi suffixes for the and instruction,
+        when OP is the appropriate immediate operand.
+
+     z: prints the third register immediate operand in assembly
+        instructions.  Outputs const0_rtx as the 'zero' register
+	instead of '0'.
+	
+     y: same as 'z', but for specifically for logical instructions,
+        where the processing for immediates are slightly different.
+
      H: for %hiadj
      L: for %lo
-     U: for upper half of 32 bit value
      D: for the upper 32-bits of a 64-bit double value
      R: prints reverse condition.
+     A: prints (reg) operand for ld[s]ex and st[s]ex.
+
+     .: print .n suffix for 16-bit instructions.
+     !: print r.n suffix for 16-bit instructions.  Used for jmpr.n.
 */
 static void
 nios2_print_operand (FILE *file, rtx op, int letter)
 {
 
+  /* First take care of the format letters that just insert a string
+     into the output stream.  */
   switch (letter)
     {
+    case '.':
+      if (current_output_insn && get_attr_length (current_output_insn) == 2)
+	fprintf (file, ".n");
+      return;
+
+    case '!':
+      if (current_output_insn && get_attr_length (current_output_insn) == 2)
+	fprintf (file, "r.n");
+      return;
+
+    case 'x':
+      if (CONST_INT_P (op))
+	{
+	  HOST_WIDE_INT val = INTVAL (op);
+	  HOST_WIDE_INT low = val & 0xffff;
+	  HOST_WIDE_INT high = (val >> 16) & 0xffff;
+
+	  if (val != 0)
+	    {
+	      if (high != 0)
+		{
+		  if (low != 0)
+		    {
+		      gcc_assert (TARGET_ARCH_R2);
+		      if (high == 0xffff)
+			fprintf (file, "c");
+		      else if (low == 0xffff)
+			fprintf (file, "ch");
+		      else
+			gcc_unreachable ();
+		    }
+		  else
+		    fprintf (file, "h");
+		}
+	      fprintf (file, "i");
+	    }
+	}
+      return;
+
+    case 'u':
     case 'i':
+      if (CONST_INT_P (op))
+	{
+	  HOST_WIDE_INT val = INTVAL (op);
+	  HOST_WIDE_INT low = val & 0xffff;
+	  HOST_WIDE_INT high = (val >> 16) & 0xffff;
+	  if (val != 0)
+	    {
+	      if (low == 0 && high != 0)
+		fprintf (file, "h");
+	      else if (high == 0 && (low & 0x8000) != 0 && letter != 'u')
+		fprintf (file, "u");
+	    }
+	}
       if (CONSTANT_P (op) && op != const0_rtx)
         fprintf (file, "i");
       return;
@@ -2064,13 +2185,18 @@ nios2_print_operand (FILE *file, rtx op,
       if (GET_CODE (op) == MEM
 	  && ((MEM_VOLATILE_P (op) && TARGET_BYPASS_CACHE_VOLATILE)
 	      || TARGET_BYPASS_CACHE))
-        fprintf (file, "io");
+	{
+	  gcc_assert (current_output_insn
+		      && get_attr_length (current_output_insn) == 4);
+	  fprintf (file, "io");
+	}
       return;
 
     default:
       break;
     }
 
+  /* Handle comparison operator names.  */
   if (comparison_operator (op, VOIDmode))
     {
       enum rtx_code cond = GET_CODE (op);
@@ -2086,10 +2212,11 @@ nios2_print_operand (FILE *file, rtx op,
 	}
     }
 
+  /* Now handle the cases where we actually need to format an operand.  */
   switch (GET_CODE (op))
     {
     case REG:
-      if (letter == 0 || letter == 'z')
+      if (letter == 0 || letter == 'z' || letter == 'y')
         {
           fprintf (file, "%s", reg_names[REGNO (op)]);
           return;
@@ -2102,19 +2229,64 @@ nios2_print_operand (FILE *file, rtx op,
       break;
 
     case CONST_INT:
-      if (INTVAL (op) == 0 && letter == 'z')
-        {
-          fprintf (file, "zero");
-          return;
-        }
+      {
+	rtx int_rtx = op;
+	HOST_WIDE_INT val = INTVAL (int_rtx);
+	HOST_WIDE_INT low = val & 0xffff;
+	HOST_WIDE_INT high = (val >> 16) & 0xffff;
+
+	if (letter == 'y')
+	  {
+	    if (val == 0)
+	      fprintf (file, "zero");
+	    else
+	      {
+		if (high != 0)
+		  {
+		    if (low != 0)
+		      {
+			gcc_assert (TARGET_ARCH_R2);
+			if (high == 0xffff)
+			  /* andci.  */
+			  int_rtx = gen_int_mode (low, SImode);
+			else if (low == 0xffff)
+			  /* andchi.  */
+			  int_rtx = gen_int_mode (high, SImode);
+			else
+			  gcc_unreachable ();
+		      }
+		    else
+		      /* andhi.  */
+		      int_rtx = gen_int_mode (high, SImode);
+		  }
+		else
+		  /* andi.  */
+		  int_rtx = gen_int_mode (low, SImode);
+		output_addr_const (file, int_rtx);
+	      }
+	    return;
+	  }
+	else if (letter == 'z')
+	  {
+	    if (val == 0)
+	      fprintf (file, "zero");
+	    else
+	      {
+		if (low == 0 && high != 0)
+		  int_rtx = gen_int_mode (high, SImode);
+		else if (low != 0)
+		  {
+		    gcc_assert (high == 0 || high == 0xffff);
+		    int_rtx = gen_int_mode (low, high == 0 ? SImode : HImode);
+		  }
+		else
+		  gcc_unreachable ();
+		output_addr_const (file, int_rtx);
+	      }
+	    return;
+	  }
+      }
 
-      if (letter == 'U')
-        {
-          HOST_WIDE_INT val = INTVAL (op);
-	  val = (val >> 16) & 0xFFFF;
-	  output_addr_const (file, gen_int_mode (val, SImode));
-          return;
-        }
       /* Else, fall through.  */
 
     case CONST:
@@ -2147,6 +2319,12 @@ nios2_print_operand (FILE *file, rtx op,
 
     case SUBREG:
     case MEM:
+      if (letter == 'A')
+	{
+	  /* Address of '(reg)' form, with no index.  */
+	  fprintf (file, "(%s)", reg_names[REGNO (XEXP (op, 0))]);
+	  return;
+	}
       if (letter == 0)
         {
           output_address (op);
@@ -3462,6 +3640,489 @@ nios2_asm_output_mi_thunk (FILE *file, t
   reload_completed = 0;
 }
 
+
+/* Utility function to break a memory address into
+   base register + constant offset.  Return false if something
+   unexpected is seen.  */
+static bool
+split_mem_address (rtx addr, rtx *base_reg, rtx *offset)
+{
+  if (REG_P (addr))
+    {
+      *base_reg = addr;
+      *offset = const0_rtx;
+      return true;
+    }
+  else if (GET_CODE (addr) == PLUS)
+    {
+      *base_reg = XEXP (addr, 0);
+      *offset = XEXP (addr, 1);
+      return true;
+    }
+  return false;
+}
+
+/* Splits out the operands of an ALU insn, places them in *LHS, *RHS1, *RHS2.  */
+static void
+split_alu_insn (rtx_insn *insn, rtx *lhs, rtx *rhs1, rtx *rhs2)
+{
+  rtx pat = PATTERN (insn);
+  gcc_assert (GET_CODE (pat) == SET);
+  *lhs = SET_DEST (pat);
+  *rhs1 = XEXP (SET_SRC (pat), 0);
+  if (GET_RTX_CLASS (GET_CODE (SET_SRC (pat))) != RTX_UNARY)
+    *rhs2 = XEXP (SET_SRC (pat), 1);
+  return;
+}
+
+/* Returns true if OP is a REG and assigned a CDX reg.  */
+static bool
+cdxreg (rtx op)
+{
+  return REG_P (op) && (!reload_completed || CDX_REG_P (REGNO (op)));
+}
+
+/* Returns true if OP is within range of CDX addi.n immediates.  */
+static bool
+cdx_add_immed (rtx op)
+{
+  if (CONST_INT_P (op))
+    {
+      HOST_WIDE_INT ival = INTVAL (op);
+      return ival <= 128 && ival > 0 && (ival & (ival - 1)) == 0;
+    }
+  return false;
+}
+
+/* Returns true if OP is within range of CDX andi.n immediates.  */
+static bool
+cdx_and_immed (rtx op)
+{
+  if (CONST_INT_P (op))
+    {
+      HOST_WIDE_INT ival = INTVAL (op);
+      return (ival == 1 || ival == 2 || ival == 3 || ival == 4
+	      || ival == 8 || ival == 0xf || ival == 0x10
+	      || ival == 0x10 || ival == 0x1f || ival == 0x20
+	      || ival == 0x3f || ival == 0x3f || ival == 0x7f
+	      || ival == 0x80 || ival == 0xff || ival == 0x7ff
+	      || ival == 0xff00 || ival == 0xffff);
+    }
+  return false;
+}
+
+/* Returns true if OP is within range of CDX movi.n immediates.  */
+static bool
+cdx_mov_immed (rtx op)
+{
+  if (CONST_INT_P (op))
+    {
+      HOST_WIDE_INT ival = INTVAL (op);
+      return ((ival >= 0 && ival <= 124)
+	      || ival == 0xff || ival == -2 || ival == -1);
+    }
+  return false;
+}
+
+/* Returns true if OP is within range of CDX slli.n/srli.n immediates.  */
+static bool
+cdx_shift_immed (rtx op)
+{
+  if (CONST_INT_P (op))
+    {
+      HOST_WIDE_INT ival = INTVAL (op);
+      return (ival == 1 || ival == 2 || ival == 3 || ival == 8
+	      || ival == 12 || ival == 16 || ival == 24
+	      || ival == 31);
+    }
+  return false;
+}
+
+
+
+/* Classification of different kinds of add instructions.  */
+enum nios2_add_insn_kind {
+  nios2_add_n_kind,
+  nios2_addi_n_kind,
+  nios2_subi_n_kind,
+  nios2_spaddi_n_kind,
+  nios2_spinci_n_kind,
+  nios2_spdeci_n_kind,
+  nios2_add_kind,
+  nios2_addi_kind
+};
+
+static const char *nios2_add_insn_names[] = {
+  "add.n", "addi.n", "subi.n", "spaddi.n",  "spinci.n", "spdeci.n",
+  "add", "addi" };
+static bool nios2_add_insn_narrow[] = {
+  true, true, true, true, true, true,
+  false, false};
+
+/* Function to classify kinds of add instruction patterns.  */
+static enum nios2_add_insn_kind 
+nios2_add_insn_classify (rtx_insn *insn ATTRIBUTE_UNUSED,
+			 rtx lhs, rtx rhs1, rtx rhs2)
+{
+  if (TARGET_HAS_CDX)
+    {
+      if (cdxreg (lhs) && cdxreg (rhs1))
+	{
+	  if (cdxreg (rhs2))
+	    return nios2_add_n_kind;
+	  if (CONST_INT_P (rhs2))
+	    {
+	      HOST_WIDE_INT ival = INTVAL (rhs2);
+	      if (ival > 0 && cdx_add_immed (rhs2))
+		return nios2_addi_n_kind;
+	      if (ival < 0 && cdx_add_immed (GEN_INT (-ival)))
+		return nios2_subi_n_kind;
+	    }
+	}
+      else if (rhs1 == stack_pointer_rtx
+	       && CONST_INT_P (rhs2))
+	{
+	  HOST_WIDE_INT imm7 = INTVAL (rhs2) >> 2;
+	  HOST_WIDE_INT rem = INTVAL (rhs2) & 3;
+	  if (rem == 0 && (imm7 & ~0x7f) == 0)
+	    {
+	      if (cdxreg (lhs))
+		return nios2_spaddi_n_kind;
+	      if (lhs == stack_pointer_rtx)
+		return nios2_spinci_n_kind;
+	    }
+	  imm7 = -INTVAL(rhs2) >> 2;
+	  rem = -INTVAL (rhs2) & 3;
+	  if (lhs == stack_pointer_rtx
+	      && rem == 0 && (imm7 & ~0x7f) == 0)
+	    return nios2_spdeci_n_kind;
+	}
+    }
+  return ((REG_P (rhs2) || rhs2 == const0_rtx)
+	  ? nios2_add_kind : nios2_addi_kind);
+}
+
+/* Emit assembly language for the different kinds of add instructions.  */
+const char*
+nios2_add_insn_asm (rtx_insn *insn, rtx *operands)
+{
+  static char buf[256];
+  int ln = 256;
+  enum nios2_add_insn_kind kind
+    = nios2_add_insn_classify (insn, operands[0], operands[1], operands[2]);
+  if (kind == nios2_subi_n_kind)
+    snprintf (buf, ln, "subi.n\t%%0, %%1, %d", (int) -INTVAL (operands[2]));
+  else if (kind == nios2_spaddi_n_kind)
+    snprintf (buf, ln, "spaddi.n\t%%0, %%2");
+  else if (kind == nios2_spinci_n_kind)
+    snprintf (buf, ln, "spinci.n\t%%2");
+  else if (kind == nios2_spdeci_n_kind)
+    snprintf (buf, ln, "spdeci.n\t%d", (int) -INTVAL (operands[2]));
+  else
+    snprintf (buf, ln, "%s\t%%0, %%1, %%z2", nios2_add_insn_names[(int)kind]);
+  return buf;
+}
+
+/* This routine, which the default "length" attribute computation is
+   based on, encapsulates information about all the cases where CDX
+   provides a narrow 2-byte instruction form.  */
+bool
+nios2_cdx_narrow_form_p (rtx_insn *insn)
+{
+  rtx pat, lhs, rhs1, rhs2;
+  enum attr_type type;
+  if (!TARGET_HAS_CDX)
+    return false;
+  type = get_attr_type (insn);
+  pat = PATTERN (insn);
+  gcc_assert (reload_completed);
+  switch (type)
+    {
+    case TYPE_CONTROL:
+      if (GET_CODE (pat) == SIMPLE_RETURN)
+	return true;
+      if (GET_CODE (pat) == PARALLEL)
+	pat = XVECEXP (pat, 0, 0);
+      if (GET_CODE (pat) == SET)
+	pat = SET_SRC (pat);
+      if (GET_CODE (pat) == IF_THEN_ELSE)
+	{
+	  /* Conditional branch patterns; for these we
+	     only check the comparison to find beqz.n/bnez.n cases.
+	     For the 'nios2_cbranch' pattern, we cannot also check
+	     the branch range here. That will be done at the md
+	     pattern "length" attribute computation.  */
+	  rtx cmp = XEXP (pat, 0);
+	  return ((GET_CODE (cmp) == EQ || GET_CODE (cmp) == NE)
+		  && cdxreg (XEXP (cmp, 0))
+		  && XEXP (cmp, 1) == const0_rtx);
+	}
+      if (GET_CODE (pat) == TRAP_IF)
+	/* trap.n is always usable.  */
+	return true;
+      if (GET_CODE (pat) == CALL)
+	pat = XEXP (XEXP (pat, 0), 0);
+      if (REG_P (pat))
+	/* Control instructions taking a register operand are indirect
+	   jumps and calls.  The CDX instructions have a 5-bit register
+	   field so any reg is valid.  */
+	return true;
+      else
+	{
+	  gcc_assert (!insn_variable_length_p (insn));
+	  return false;
+	}
+    case TYPE_ADD:
+      {
+	enum nios2_add_insn_kind kind;
+	split_alu_insn (insn, &lhs, &rhs1, &rhs2);
+	kind = nios2_add_insn_classify (insn, lhs, rhs1, rhs2);
+	return nios2_add_insn_narrow[(int)kind];
+      }
+    case TYPE_LD:
+      {
+	bool ret;
+	HOST_WIDE_INT offset, rem = 0;
+	rtx addr, reg = SET_DEST (pat), mem = SET_SRC (pat);
+	if (GET_CODE (mem) == SIGN_EXTEND)
+	  /* No CDX form for sign-extended load.  */
+	  return false;
+	if (GET_CODE (mem) == ZERO_EXTEND)
+	  /* The load alternatives in the zero_extend* patterns.  */
+	  mem = XEXP (mem, 0);
+	if (MEM_P (mem))
+	  {
+	    /* ldxio.  */
+	    if ((MEM_VOLATILE_P (mem) && TARGET_BYPASS_CACHE_VOLATILE)
+		|| TARGET_BYPASS_CACHE)
+	      return false;
+	    addr = XEXP (mem, 0);
+	    /* GP-based references are never narrow.  */
+	    if (gprel_constant_p (addr))
+		return false;
+	    ret = split_mem_address (addr, &rhs1, &rhs2);
+	    gcc_assert (ret);
+	  }
+	else
+	  return false;
+
+	offset = INTVAL (rhs2);
+	if (GET_MODE (mem) == SImode)
+	  {
+	    rem = offset & 3;
+	    offset >>= 2;
+	    /* ldwsp.n case.  */
+	    if (rtx_equal_p (rhs1, stack_pointer_rtx)
+		&& rem == 0 && (offset & ~0x1f) == 0)
+	      return true;
+	  }
+	else if (GET_MODE (mem) == HImode)
+	  {
+	    rem = offset & 1;
+	    offset >>= 1;
+	  }
+	/* ldbu.n, ldhu.n, ldw.n cases.  */
+	return (cdxreg (reg) && cdxreg (rhs1)
+		&& rem == 0 && (offset & ~0xf) == 0);
+      }
+    case TYPE_ST:
+      if (GET_CODE (pat) == PARALLEL)
+	/* stex, stsex.  */
+	return false;
+      else
+	{
+	  bool ret;
+	  HOST_WIDE_INT offset, rem = 0;
+	  rtx addr, reg = SET_SRC (pat), mem = SET_DEST (pat);
+	  if (!MEM_P (mem))
+	    return false;
+	  /* stxio.  */
+	  if ((MEM_VOLATILE_P (mem) && TARGET_BYPASS_CACHE_VOLATILE)
+	      || TARGET_BYPASS_CACHE)
+	    return false;
+	  addr = XEXP (mem, 0);
+	  /* GP-based references are never narrow.  */
+	  if (gprel_constant_p (addr))
+	    return false;
+	  ret = split_mem_address (addr, &rhs1, &rhs2);
+	  gcc_assert (ret);
+	  offset = INTVAL (rhs2);
+	  if (GET_MODE (mem) == SImode)
+	    {
+	      rem = offset & 3;
+	      offset >>= 2;
+	      /* stwsp.n case.  */
+	      if (rtx_equal_p (rhs1, stack_pointer_rtx)
+		  && rem == 0 && (offset & ~0x1f) == 0)
+		return true;
+	      /* stwz.n case.  */
+	      else if (reg == const0_rtx && cdxreg (rhs1)
+		       && rem == 0 && (offset & ~0x3f) == 0)
+		return true;
+	    }
+	  else if (GET_MODE (mem) == HImode)
+	    {
+	      rem = offset & 1;
+	      offset >>= 1;
+	    }
+	  else
+	    {
+	      gcc_assert (GET_MODE (mem) == QImode);
+	      /* stbz.n case.  */
+	      if (reg == const0_rtx && cdxreg (rhs1)
+		  && (offset & ~0x3f) == 0)
+		return true;
+	    }
+
+	  /* stbu.n, sthu.n, stw.n cases.  */
+	  return (cdxreg (reg) && cdxreg (rhs1)
+		  && rem == 0 && (offset & ~0xf) == 0);
+	}
+    case TYPE_MOV:
+      lhs = SET_DEST (pat);
+      rhs1 = SET_SRC (pat);
+      if (CONST_INT_P (rhs1))
+	return (cdxreg (lhs) && cdx_mov_immed (rhs1));
+      gcc_assert (REG_P (lhs) && REG_P (rhs1));
+      return true;
+
+    case TYPE_AND:
+      /* Some zero_extend* alternatives are and insns.  */
+      if (GET_CODE (SET_SRC (pat)) == ZERO_EXTEND)
+	return (cdxreg (SET_DEST (pat))
+		&& cdxreg (XEXP (SET_SRC (pat), 0)));
+      split_alu_insn (insn, &lhs, &rhs1, &rhs2);
+      if (CONST_INT_P (rhs2))
+	return (cdxreg (lhs) && cdxreg (rhs1) && cdx_and_immed (rhs2));
+      return (cdxreg (lhs) && cdxreg (rhs2)
+	      && (!reload_completed || rtx_equal_p (lhs, rhs1)));
+
+    case TYPE_OR:
+    case TYPE_XOR:
+      /* Note the two-address limitation for CDX form.  */
+      split_alu_insn (insn, &lhs, &rhs1, &rhs2);
+      return (cdxreg (lhs) && cdxreg (rhs2)
+	      && (!reload_completed || rtx_equal_p (lhs, rhs1)));
+
+    case TYPE_SUB:
+      split_alu_insn (insn, &lhs, &rhs1, &rhs2);
+      return (cdxreg (lhs) && cdxreg (rhs1) && cdxreg (rhs2));
+
+    case TYPE_NEG:
+    case TYPE_NOT:
+      split_alu_insn (insn, &lhs, &rhs1, NULL);
+      return (cdxreg (lhs) && cdxreg (rhs1));
+
+    case TYPE_SLL:
+    case TYPE_SRL:
+      split_alu_insn (insn, &lhs, &rhs1, &rhs2);
+      return (cdxreg (lhs)
+	      && ((cdxreg (rhs1) && cdx_shift_immed (rhs2))
+		  || (cdxreg (rhs2)
+		      && (!reload_completed || rtx_equal_p (lhs, rhs1)))));
+    case TYPE_NOP:
+    case TYPE_PUSH:
+    case TYPE_POP:
+      return true;
+    default:
+      break;
+    }
+  return false;
+}
+
+/* Implement TARGET_MACHINE_DEPENDENT_REORG:
+   We use this hook when emitting CDX code to enforce the 4-byte
+   alignment requirement for labels that are used as the targets of
+   jmpi instructions.  CDX code can otherwise contain a mix of 16-bit
+   and 32-bit instructions aligned on any 16-bit boundary, but functions
+   and jmpi labels have to be 32-bit aligned because of the way the address
+   is encoded in the instruction.  */
+
+static unsigned char *label_align;
+static int min_labelno, max_labelno;
+
+static void
+nios2_reorg (void)
+{
+  bool changed = true;
+  rtx_insn *insn;
+
+  if (!TARGET_HAS_CDX)
+    return;
+
+  /* Initialize the data structures.  */
+  if (label_align)
+    free (label_align);
+  max_labelno = max_label_num ();
+  min_labelno = get_first_label_num ();
+  label_align = XCNEWVEC (unsigned char, max_labelno - min_labelno + 1);
+  
+  /* Iterate on inserting alignment and adjusting branch lengths until
+     no more changes.  */
+  while (changed)
+    {
+      changed = false;
+      shorten_branches (get_insns ());
+
+      for (insn = get_insns (); insn != 0; insn = NEXT_INSN (insn))
+	if (JUMP_P (insn) && insn_variable_length_p (insn))
+	  {
+	    rtx label = JUMP_LABEL (insn);
+	    /* We use the current fact that all cases of 'jmpi'
+	       doing the actual branch in the machine description
+	       has a computed length of 6 or 8.  Length 4 and below
+	       are all PC-relative 'br' branches without the jump-align
+	       problem.  */
+	    if (label && LABEL_P (label) && get_attr_length (insn) > 4)
+	      {
+		int index = CODE_LABEL_NUMBER (label) - min_labelno;
+		if (label_align[index] != 2)
+		  {
+		    label_align[index] = 2;
+		    changed = true;
+		  }
+	      }
+	  }
+    }
+}
+
+/* Implement LABEL_ALIGN, using the information gathered in nios2_reorg.  */
+int
+nios2_label_align (rtx label)
+{
+  int n = CODE_LABEL_NUMBER (label);
+
+  if (label_align && n >= min_labelno && n <= max_labelno)
+    return MAX (label_align[n - min_labelno], align_labels_log);
+  return align_labels_log;
+}
+
+/* Implement ADJUST_REG_ALLOC_ORDER.  We use the default ordering
+   for R1 and non-CDX R2 code; for CDX we tweak thing to prefer
+   the registers that can be used as operands to instructions that
+   have 3-bit register fields.  */
+void
+nios2_adjust_reg_alloc_order (void)
+{
+  const int cdx_reg_alloc_order[] =
+    {
+      /* Call-clobbered GPRs within CDX 3-bit encoded range.  */
+      2, 3, 4, 5, 6, 7, 
+      /* Call-saved GPRs within CDX 3-bit encoded range.  */
+      16, 17,
+      /* Other call-clobbered GPRs.  */
+      8, 9, 10, 11, 12, 13, 14, 15,
+      /* Other call-saved GPRs. RA placed first since it is always saved.  */
+      31, 18, 19, 20, 21, 22, 23, 28,
+      /* Fixed GPRs, not used by the register allocator.  */
+      0, 1, 24, 25, 26, 27, 29, 30, 32, 33, 34, 35, 36, 37, 38, 39
+   };
+
+  if (TARGET_HAS_CDX)
+    memcpy (reg_alloc_order, cdx_reg_alloc_order,
+	    sizeof (int) * FIRST_PSEUDO_REGISTER);
+}
+
 
 /* Initialize the GCC target structure.  */
 #undef TARGET_ASM_FUNCTION_PROLOGUE
@@ -3549,6 +4210,9 @@ nios2_asm_output_mi_thunk (FILE *file, t
 #undef TARGET_ASM_OUTPUT_DWARF_DTPREL
 #define TARGET_ASM_OUTPUT_DWARF_DTPREL nios2_output_dwarf_dtprel
 
+#undef TARGET_PRINT_OPERAND_PUNCT_VALID_P
+#define TARGET_PRINT_OPERAND_PUNCT_VALID_P nios2_print_operand_punct_valid_p
+
 #undef TARGET_PRINT_OPERAND
 #define TARGET_PRINT_OPERAND nios2_print_operand
 
@@ -3589,6 +4253,9 @@ nios2_asm_output_mi_thunk (FILE *file, t
 #undef  TARGET_ASM_OUTPUT_MI_THUNK
 #define TARGET_ASM_OUTPUT_MI_THUNK nios2_asm_output_mi_thunk
 
+#undef TARGET_MACHINE_DEPENDENT_REORG
+#define TARGET_MACHINE_DEPENDENT_REORG nios2_reorg
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 #include "gt-nios2.h"
Index: gcc/config/nios2/constraints.md
===================================================================
--- gcc/config/nios2/constraints.md	(revision 225793)
+++ gcc/config/nios2/constraints.md	(working copy)
@@ -20,9 +20,10 @@
 
 ;; We use the following constraint letters for constants
 ;;
-;;  I: -32768 to -32767
+;;  I: -32768 to 32767
 ;;  J: 0 to 65535
 ;;  K: $nnnn0000 for some nnnn
+;;  P: Under R2, $nnnnffff or $ffffnnnn for some nnnn
 ;;  L: 0 to 31 (for shift counts)
 ;;  M: 0
 ;;  N: 0 to 255 (for custom instruction numbers)
@@ -86,6 +87,11 @@
   (and (match_code "const_int")
        (match_test "ival >= 0 && ival <= 31")))
 
+(define_constraint "P"
+  "An immediate operand for R2 andchi/andci instructions."
+  (and (match_code "const_int")
+       (match_test "TARGET_ARCH_R2 && ANDCLEAR_INT (ival)")))
+
 (define_constraint "S"
   "An immediate stored in small data, accessible by GP."
   (match_test "gprel_constant_p (op)"))
Index: gcc/config/nios2/predicates.md
===================================================================
--- gcc/config/nios2/predicates.md	(revision 225793)
+++ gcc/config/nios2/predicates.md	(working copy)
@@ -55,6 +55,16 @@
   (ior (match_operand 0 "const_logical_operand")
        (match_operand 0 "register_operand")))
 
+(define_predicate "const_and_operand"
+  (and (match_code "const_int")
+       (match_test "SMALL_INT_UNSIGNED (INTVAL (op))
+                    || UPPER16_INT (INTVAL (op))
+                    || (TARGET_ARCH_R2 && ANDCLEAR_INT (INTVAL (op)))")))
+
+(define_predicate "and_operand"
+  (ior (match_operand 0 "const_and_operand")
+       (match_operand 0 "register_operand")))
+
 (define_predicate "const_shift_operand"
   (and (match_code "const_int")
        (match_test "SHIFT_INT (INTVAL (op))")))
@@ -84,6 +94,16 @@
                                          false));
 })
 
+(define_predicate "stack_memory_operand"
+  (match_code "mem")
+{
+  rtx addr = XEXP (op, 0);
+  return ((REG_P (addr) && REGNO (addr) == SP_REGNO)
+          || (GET_CODE (addr) == PLUS
+              && REG_P (XEXP (addr, 0)) && REGNO (XEXP (addr, 0)) == SP_REGNO
+              && CONST_INT_P (XEXP (addr, 1))));
+})
+
 (define_predicate "ldstio_memory_operand"
   (match_code "mem")
 {
Index: gcc/config/nios2/nios2.md
===================================================================
--- gcc/config/nios2/nios2.md	(revision 225793)
+++ gcc/config/nios2/nios2.md	(working copy)
@@ -30,6 +30,7 @@
 
    (TP_REGNO              23)	; Thread pointer register
    (GP_REGNO	          26)	; Global pointer register
+   (SP_REGNO	          27)	; Stack pointer register
    (FP_REGNO	          28)	; Frame pointer register
    (EA_REGNO	          29)	; Exception return address register
    (RA_REGNO              31)	; Return address register
@@ -92,9 +93,14 @@
 ; incuring a stall.
 
 ; length of an instruction (in bytes)
-(define_attr "length" "" (const_int 4))
+(define_attr "length" ""
+  (if_then_else (match_test "nios2_cdx_narrow_form_p (insn)")
+    (const_int 2)
+    (const_int 4)))
+
 (define_attr "type" 
-  "unknown,complex,control,alu,cond_alu,st,ld,shift,mul,div,custom" 
+  "unknown,complex,control,alu,cond_alu,st,ld,stwm,ldwm,push,pop,mul,div,\
+   custom,add,sub,mov,and,or,xor,neg,not,sll,srl,sra,rol,ror,nop"
   (const_string "complex"))
 
 (define_asm_attributes
@@ -118,11 +124,11 @@
   "cpu")
 
 (define_insn_reservation "control" 1
-  (eq_attr "type" "control")
+  (eq_attr "type" "control,pop")
   "cpu")
 
 (define_insn_reservation "alu" 1
-  (eq_attr "type" "alu")
+  (eq_attr "type" "alu,add,sub,mov,and,or,xor,neg,not")
   "cpu")
 
 (define_insn_reservation "cond_alu" 1
@@ -130,7 +136,7 @@
   "cpu")
 
 (define_insn_reservation "st" 1
-  (eq_attr "type" "st")
+  (eq_attr "type" "st,stwm,push")
   "cpu")
   
 (define_insn_reservation "custom" 1
@@ -139,11 +145,11 @@
 
 ; shifts, muls and lds have three cycle latency
 (define_insn_reservation "ld" 3
-  (eq_attr "type" "ld")
+  (eq_attr "type" "ld,ldwm")
   "cpu")
 
 (define_insn_reservation "shift" 3
-  (eq_attr "type" "shift")
+  (eq_attr "type" "sll,srl,sra,rol,ror")
   "cpu")
 
 (define_insn_reservation "mul" 3
@@ -171,46 +177,90 @@
     DONE;
 })
 
+(define_insn "*high"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+        (high:SI (match_operand:SI 1 "immediate_operand" "i")))]
+  ""
+  "movhi\\t%0, %H1"
+  [(set_attr "type" "alu")])
+
+(define_insn "*lo_sum"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+        (lo_sum:SI (match_operand:SI 1 "register_operand"  "r")
+                   (match_operand:SI 2 "immediate_operand" "i")))]
+  ""
+  "addi\\t%0, %1, %L2"
+  [(set_attr "type" "alu")])
+
 (define_insn "movqi_internal"
-  [(set (match_operand:QI 0 "nonimmediate_operand" "=m, r,r, r")
-        (match_operand:QI 1 "general_operand"       "rM,m,rM,I"))]
+  [(set (match_operand:QI 0 "nonimmediate_operand" "=m, r,r")
+        (match_operand:QI 1 "general_operand"       "rM,m,rI"))]
   "(register_operand (operands[0], QImode)
     || reg_or_0_operand (operands[1], QImode))"
-  "@
-    stb%o0\\t%z1, %0
-    ldbu%o1\\t%0, %1
-    mov\\t%0, %z1
-    movi\\t%0, %1"
-  [(set_attr "type" "st,ld,alu,alu")])
+  {
+    switch (which_alternative)
+      {
+      case 0:
+	if (get_attr_length (insn) != 2)
+	  return "stb%o0\\t%z1, %0";
+	else if (const_0_operand (operands[1], QImode))
+	  return "stbz.n\\t%z1, %0";
+	else
+	  return "stb.n\\t%z1, %0";
+      case 1:
+	return "ldbu%o1%.\\t%0, %1";
+      case 2:
+	return "mov%i1%.\\t%0, %z1";
+      default:
+	gcc_unreachable ();
+      }
+  }
+  [(set_attr "type" "st,ld,mov")])
 
 (define_insn "movhi_internal"
-  [(set (match_operand:HI 0 "nonimmediate_operand" "=m, r,r, r")
-        (match_operand:HI 1 "general_operand"       "rM,m,rM,I"))]
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=m, r,r")
+        (match_operand:HI 1 "general_operand"       "rM,m,rI"))]
   "(register_operand (operands[0], HImode)
     || reg_or_0_operand (operands[1], HImode))"
   "@
-    sth%o0\\t%z1, %0
-    ldhu%o1\\t%0, %1
-    mov\\t%0, %z1
-    movi\\t%0, %1"
-  [(set_attr "type" "st,ld,alu,alu")])
+    sth%o0%.\\t%z1, %0
+    ldhu%o1%.\\t%0, %1
+    mov%i1%.\\t%0, %z1"
+  [(set_attr "type" "st,ld,mov")])
 
 (define_insn "movsi_internal"
-  [(set (match_operand:SI 0 "nonimmediate_operand" "=m, r,r, r,r,r,r,r")
-        (match_operand:SI 1 "general_operand"       "rM,m,rM,I,J,K,S,i"))]
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=m, r,r,   r")
+        (match_operand:SI 1 "general_operand"       "rM,m,rIJK,S"))]
   "(register_operand (operands[0], SImode)
     || reg_or_0_operand (operands[1], SImode))"
-  "@
-    stw%o0\\t%z1, %0
-    ldw%o1\\t%0, %1
-    mov\\t%0, %z1
-    movi\\t%0, %1
-    movui\\t%0, %1
-    movhi\\t%0, %H1
-    addi\\t%0, gp, %%gprel(%1)
-    movhi\\t%0, %H1\;addi\\t%0, %0, %L1"
-  [(set_attr "type" "st,ld,alu,alu,alu,alu,alu,alu")
-   (set_attr "length" "4,4,4,4,4,4,4,8")])
+  {
+    switch (which_alternative)
+      {
+      case 0:
+	if (get_attr_length (insn) != 2)
+	  return "stw%o0\\t%z1, %0";
+	else if (stack_memory_operand (operands[0], SImode))
+	  return "stwsp.n\\t%z1, %0";
+	else if (const_0_operand (operands[1], SImode))
+	  return "stwz.n\\t%z1, %0";
+	else
+	  return "stw.n\\t%z1, %0";
+      case 1:
+	if (get_attr_length (insn) != 2)
+	  return "ldw%o1\\t%0, %1";
+	else if (stack_memory_operand (operands[1], SImode))
+	  return "ldwsp.n\\t%0, %1";
+	else
+	  return "ldw.n\\t%0, %1";
+      case 2:
+	return "mov%i1%.\\t%0, %z1";
+      case 3:
+	return "addi\\t%0, gp, %%gprel(%1)";
+      default:
+	gcc_unreachable ();
+      }
+  }
+  [(set_attr "type" "st,ld,mov,alu")])
 
 (define_mode_iterator BH [QI HI])
 (define_mode_iterator BHW [QI HI SI])
@@ -264,18 +314,18 @@
         (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r,m")))]
   ""
   "@
-    andi\\t%0, %1, 0xffff
-    ldhu%o1\\t%0, %1"
-  [(set_attr "type"     "alu,ld")])
+    andi%.\\t%0, %1, 0xffff
+    ldhu%o1%.\\t%0, %1"
+  [(set_attr "type"     "and,ld")])
 
 (define_insn "zero_extendqi<mode>2"
   [(set (match_operand:QX 0 "register_operand" "=r,r")
         (zero_extend:QX (match_operand:QI 1 "nonimmediate_operand" "r,m")))]
   ""
   "@
-    andi\\t%0, %1, 0xff
-    ldbu%o1\\t%0, %1"
-  [(set_attr "type"     "alu,ld")])
+    andi%.\\t%0, %1, 0xff
+    ldbu%o1%.\\t%0, %1"
+  [(set_attr "type"     "and,ld")])
 
 ;; Sign extension patterns
 
@@ -285,7 +335,7 @@
   ""
   "@
    #
-   ldh%o1\\t%0, %1"
+   ldh%o1%.\\t%0, %1"
   [(set_attr "type" "alu,ld")])
 
 (define_insn "extendqi<mode>2"
@@ -294,7 +344,7 @@
   ""
   "@
    #
-   ldb%o1\\t%0, %1"
+   ldb%o1%.\\t%0, %1"
   [(set_attr "type" "alu,ld")])
 
 ;; Split patterns for register alternative cases.
@@ -331,16 +381,18 @@
         (plus:SI (match_operand:SI 1 "register_operand"   "%r")
                  (match_operand:SI 2 "add_regimm_operand" "rIT")))]
   ""
-  "add%i2\\t%0, %1, %z2"
-  [(set_attr "type" "alu")])
+{
+  return nios2_add_insn_asm (insn, operands);
+}
+  [(set_attr "type" "add")])
 
 (define_insn "subsi3"
   [(set (match_operand:SI 0 "register_operand"           "=r")
         (minus:SI (match_operand:SI 1 "reg_or_0_operand" "rM")
                   (match_operand:SI 2 "register_operand" "r")))]
   ""
-  "sub\\t%0, %z1, %2"
-  [(set_attr "type" "alu")])
+  "sub%.\\t%0, %z1, %2"
+  [(set_attr "type" "sub")])
 
 (define_insn "mulsi3"
   [(set (match_operand:SI 0 "register_operand"          "=r")
@@ -422,32 +474,47 @@
   [(set (match_operand:SI 0 "register_operand"        "=r")
         (neg:SI (match_operand:SI 1 "register_operand" "r")))]
   ""
-  "sub\\t%0, zero, %1"
-  [(set_attr "type" "alu")])
+{
+  if (get_attr_length (insn) == 2)
+    return "neg.n\\t%0, %1";
+  else
+    return "sub\\t%0, zero, %1";
+}
+  [(set_attr "type" "neg")])
 
 (define_insn "one_cmplsi2"
   [(set (match_operand:SI 0 "register_operand"        "=r")
         (not:SI (match_operand:SI 1 "register_operand" "r")))]
   ""
-  "nor\\t%0, zero, %1"
-  [(set_attr "type" "alu")])
+{
+  if (get_attr_length (insn) == 2)
+    return "not.n\\t%0, %1";
+  else
+    return "nor\\t%0, zero, %1";
+}
+  [(set_attr "type" "not")])
 
 
 ;;  Integer logical Operations
 
-(define_code_iterator LOGICAL [and ior xor])
-(define_code_attr logical_asm [(and "and") (ior "or") (xor "xor")])
+(define_insn "andsi3"
+  [(set (match_operand:SI 0 "register_operand"          "=r")
+        (and:SI (match_operand:SI 1 "register_operand"  "%r")
+                (match_operand:SI 2 "and_operand"     "rJKP")))]
+  ""
+  "and%x2%.\\t%0, %1, %y2"
+  [(set_attr "type" "and")])
+
+(define_code_iterator LOGICAL [ior xor])
+(define_code_attr logical_asm [(ior "or") (xor "xor")])
 
 (define_insn "<code>si3"
-  [(set (match_operand:SI 0 "register_operand"             "=r,r,r")
-        (LOGICAL:SI (match_operand:SI 1 "register_operand" "%r,r,r")
-                    (match_operand:SI 2 "logical_operand"  "rM,J,K")))]
+  [(set (match_operand:SI 0 "register_operand"             "=r")
+        (LOGICAL:SI (match_operand:SI 1 "register_operand" "%r")
+                    (match_operand:SI 2 "logical_operand" "rJK")))]
   ""
-  "@
-    <logical_asm>\\t%0, %1, %z2
-    <logical_asm>%i2\\t%0, %1, %2
-    <logical_asm>h%i2\\t%0, %1, %U2"
-  [(set_attr "type" "alu")])
+  "<logical_asm>%x2%.\\t%0, %1, %y2"
+  [(set_attr "type" "<logical_asm>")])
 
 (define_insn "*norsi3"
   [(set (match_operand:SI 0 "register_operand"                 "=r")
@@ -471,8 +538,8 @@
         (SHIFT:SI (match_operand:SI 1 "register_operand" "r")
                   (match_operand:SI 2 "shift_operand"    "rL")))]
   ""
-  "<shift_asm>%i2\\t%0, %1, %z2"
-  [(set_attr "type" "shift")])
+  "<shift_asm>%i2%.\\t%0, %1, %z2"
+  [(set_attr "type" "<shift_asm>")])
 
 (define_insn "rotrsi3"
   [(set (match_operand:SI 0 "register_operand"             "=r")
@@ -480,7 +547,48 @@
                      (match_operand:SI 2 "register_operand" "r")))]
   ""
   "ror\\t%0, %1, %2"
-  [(set_attr "type" "shift")])
+  [(set_attr "type" "ror")])
+
+;; Nios II R2 Bit Manipulation Extension (BMX), provides
+;; bit merge/insertion/extraction instructions.
+
+(define_insn "*merge"
+  [(set (zero_extract:SI (match_operand:SI 0 "register_operand"   "+r")
+			 (match_operand:SI 1 "const_shift_operand" "L")
+			 (match_operand:SI 2 "const_shift_operand" "L"))
+        (zero_extract:SI (match_operand:SI 3 "register_operand"    "r")
+                         (match_dup 1) (match_dup 2)))]
+  "TARGET_HAS_BMX"
+{
+  operands[4] = GEN_INT (INTVAL (operands[1]) + INTVAL (operands[2]) - 1);
+  return "merge\\t%0, %3, %4, %2";
+}
+  [(set_attr "type" "alu")])
+
+(define_insn "extzv"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+        (zero_extract:SI (match_operand:SI 1 "register_operand"    "r")
+                         (match_operand:SI 2 "const_shift_operand" "L")
+                         (match_operand:SI 3 "const_shift_operand" "L")))]
+  "TARGET_HAS_BMX"
+{
+  operands[4] = GEN_INT (INTVAL (operands[2]) + INTVAL (operands[3]) - 1);
+  return "extract\\t%0, %1, %4, %3";
+}
+  [(set_attr "type" "alu")])
+
+(define_insn "insv"
+  [(set (zero_extract:SI (match_operand:SI 0 "register_operand"   "+r")
+			 (match_operand:SI 1 "const_shift_operand" "L")
+			 (match_operand:SI 2 "const_shift_operand" "L"))
+	(match_operand:SI 3 "reg_or_0_operand" "rM"))]
+  "TARGET_HAS_BMX"
+{
+  operands[4] = GEN_INT (INTVAL (operands[1]) + INTVAL (operands[2]) - 1);
+  return "insert\\t%0, %z3, %4, %2";
+}
+  [(set_attr "type" "alu")])
+
 
 
 ;; Floating point instructions
@@ -635,15 +743,16 @@
   DONE;
 })
 
-(define_insn "return"
+(define_expand "return"
   [(simple_return)]
   "nios2_can_use_return_insn ()"
-  "ret")
+  "")
 
 (define_insn "simple_return"
   [(simple_return)]
   ""
-  "ret")
+  "ret%."
+  [(set_attr "type" "control")])
 
 ;; Block any insns from being moved before this point, since the
 ;; profiling call to mcount can use various registers that aren't
@@ -699,7 +808,7 @@
 (define_insn "indirect_jump"
   [(set (pc) (match_operand:SI 0 "register_operand" "c"))]
   ""
-  "jmp\\t%0"
+  "jmp%!\\t%0"
   [(set_attr "type" "control")])
 
 (define_insn "jump"
@@ -707,7 +816,9 @@
         (label_ref (match_operand 0 "" "")))]
   ""
   {
-    if (flag_pic || get_attr_length (insn) == 4)
+    if (get_attr_length (insn) == 2)
+      return "br.n\\t%0";
+    else if (get_attr_length (insn) == 4)
       return "br\\t%0";
     else
       return "jmpi\\t%0";
@@ -715,11 +826,16 @@
   [(set_attr "type" "control")
    (set (attr "length") 
         (if_then_else
-	    (and (ge (minus (match_dup 0) (pc)) (const_int -32768))
-	         (le (minus (match_dup 0) (pc)) (const_int 32764)))
-	    (const_int 4)
-	    (const_int 8)))])
-
+	    (and (match_test "TARGET_HAS_CDX")
+	         (and (ge (minus (match_dup 0) (pc)) (const_int -1022))
+	              (le (minus (match_dup 0) (pc)) (const_int 1022))))
+	    (const_int 2)
+	    (if_then_else
+	        (ior (match_test "flag_pic")
+	             (and (ge (minus (match_dup 0) (pc)) (const_int -32764))
+	                  (le (minus (match_dup 0) (pc)) (const_int 32764))))
+	        (const_int 4)
+	        (const_int 8))))])
 
 (define_expand "call"
   [(parallel [(call (match_operand 0 "" "")
@@ -743,7 +859,7 @@
   ""
   "@
    call\\t%0
-   callr\\t%0"
+   callr%.\\t%0"
   [(set_attr "type" "control")])
 
 (define_insn "*call_value"
@@ -754,7 +870,7 @@
   ""
   "@
    call\\t%1
-   callr\\t%1"
+   callr%.\\t%1"
   [(set_attr "type" "control")])
 
 (define_expand "sibcall"
@@ -779,7 +895,7 @@
   ""
   "@
    jmpi\\t%0
-   jmp\\t%0"
+   jmp%!\\t%0"
   [(set_attr "type" "control")])
 
 (define_insn "sibcall_value_internal"
@@ -790,7 +906,7 @@
   ""
   "@
    jmpi\\t%1
-   jmp\\t%1"
+   jmp%!\\t%1"
   [(set_attr "type" "control")])
 
 (define_expand "tablejump"
@@ -814,7 +930,7 @@
         (match_operand:SI 0 "register_operand" "c"))
    (use (label_ref (match_operand 1 "" "")))]
   ""
-  "jmp\\t%0"
+  "jmp%!\\t%0"
   [(set_attr "type" "control")])
 
 
@@ -868,18 +984,30 @@
        (label_ref (match_operand 3 "" ""))
        (pc)))]
   ""
-  {
-    if (flag_pic || get_attr_length (insn) == 4)
-      return "b%0\t%z1, %z2, %l3";
-    else
-      return "b%R0\t%z1, %z2, .+8;jmpi\t%l3";
-  }
+{
+  if (get_attr_length (insn) == 2)
+    return "b%0z.n\t%z1, %l3";
+  else if (get_attr_length (insn) == 4)
+    return "b%0\t%z1, %z2, %l3";
+  else if (get_attr_length (insn) == 6)
+    return "b%R0z.n\t%z1, .+6;jmpi\t%l3";
+  else
+    return "b%R0\t%z1, %z2, .+8;jmpi\t%l3";
+}
   [(set_attr "type" "control")
    (set (attr "length") 
-        (if_then_else
-	    (and (ge (minus (match_dup 3) (pc)) (const_int -32768))
-	         (le (minus (match_dup 3) (pc)) (const_int 32764)))
-	    (const_int 4) (const_int 8)))])
+        (cond
+         [(and (match_test "nios2_cdx_narrow_form_p (insn)")
+               (ge (minus (match_dup 3) (pc)) (const_int -126))
+               (le (minus (match_dup 3) (pc)) (const_int 126)))
+          (const_int 2)
+          (ior (match_test "flag_pic")
+               (and (ge (minus (match_dup 3) (pc)) (const_int -32764))
+                    (le (minus (match_dup 3) (pc)) (const_int 32764))))
+          (const_int 4)
+          (match_test "nios2_cdx_narrow_form_p (insn)")
+          (const_int 6)]
+         (const_int 8)))])
 
 ;; Floating point comparisons
 (define_code_iterator FCMP [eq ne gt ge le lt])
@@ -917,7 +1045,7 @@
         (UCMP:SI (match_operand:SI 1 "reg_or_0_operand"  "rM")
                  (match_operand:SI 2 "uns_arith_operand" "rJ")))]
   ""
-  "cmp<code>%i2\\t%0, %z1, %z2"
+  "cmp<code>%u2\\t%0, %z1, %z2"
   [(set_attr "type" "alu")])
 
 
@@ -951,8 +1079,8 @@
 (define_insn "nop"
   [(const_int 0)]
   ""
-  "nop"
-  [(set_attr "type" "alu")])
+  "nop%."
+  [(set_attr "type" "nop")])
 
 ;; Connect 'sync' to 'memory_barrier' standard expand name
 (define_expand "memory_barrier"
@@ -1000,7 +1128,7 @@
 (define_insn "trap"
   [(trap_if (const_int 1) (const_int 3))]
   ""
-  "trap\\t3"
+  "trap%.\\t3"
   [(set_attr "type" "control")])
 
 (define_insn "ctrapsi4"
@@ -1009,9 +1137,16 @@
                (match_operand:SI 2 "reg_or_0_operand" "rM")])
             (match_operand 3 "const_int_operand" "i"))]
   ""
-  "b%R0\\t%z1, %z2, 1f\;trap\\t%3\;1:"
+{
+  if (get_attr_length (insn) == 6)
+    return "b%R0\\t%z1, %z2, 1f\;trap.n\\t%3\;1:";
+  else
+    return "b%R0\\t%z1, %z2, 1f\;trap\\t%3\;1:";
+}
   [(set_attr "type" "control")
-   (set_attr "length" "8")])
+   (set (attr "length")
+        (if_then_else (match_test "nios2_cdx_narrow_form_p (insn)")
+                      (const_int 6) (const_int 8)))])
   
 ;; Load the GOT register.
 (define_insn "load_got_register"
Index: gcc/doc/md.texi
===================================================================
--- gcc/doc/md.texi	(revision 225793)
+++ gcc/doc/md.texi	(working copy)
@@ -2991,6 +2991,9 @@ instead of @code{0} in the assembly outp
 Integer that is valid as an immediate operand for
 a custom instruction opcode. Range 0 to 255.
 
+@item P
+An immediate operand for R2 andchi/andci instructions. 
+
 @item S
 Matches immediates which are addresses in the small
 data section and therefore can be added to @code{gp}
Index: gcc/testsuite/gcc.target/nios2/andci.c
===================================================================
--- gcc/testsuite/gcc.target/nios2/andci.c	(revision 0)
+++ gcc/testsuite/gcc.target/nios2/andci.c	(revision 0)
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=r2" } */
+
+/* Test generation of Nios II R2 "andci" and "andchi" instructions.  */
+
+unsigned int f (unsigned int a)
+{
+  return a & 0xfffffff0;
+}
+
+unsigned int g (unsigned int b)
+{
+  return b & 0xfff0ffff;
+}
+
+/* { dg-final { scan-assembler "\tandci\t.*" } }  */
+/* { dg-final { scan-assembler "\tandchi\t.*" } }  */
+
Index: gcc/testsuite/gcc.target/nios2/bmx.c
===================================================================
--- gcc/testsuite/gcc.target/nios2/bmx.c	(revision 0)
+++ gcc/testsuite/gcc.target/nios2/bmx.c	(revision 0)
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=r2 -mbmx" } */
+
+/* Test generation of Nios II R2 BMX instructions.  */
+
+struct s {
+  unsigned int pad1 : 3;
+  unsigned int bitfield : 20;
+  unsigned int intfield;
+};
+
+void f (struct s *a, struct s *b)
+{
+  a->bitfield = b->bitfield;
+}
+
+void g (struct s *a, struct s *b)
+{
+  a->bitfield = b->intfield;
+}
+
+void h (struct s *a, struct s *b)
+{
+  a->intfield = b->bitfield;
+}
+
+/* { dg-final { scan-assembler "\tmerge\t.*, 22, 3" } }  */
+/* { dg-final { scan-assembler "\tinsert\t.*, 22, 3" } }  */
+/* { dg-final { scan-assembler "\textract\t.*, 22, 3" } }  */
Index: gcc/testsuite/gcc.target/nios2/cdx-add.c
===================================================================
--- gcc/testsuite/gcc.target/nios2/cdx-add.c	(revision 0)
+++ gcc/testsuite/gcc.target/nios2/cdx-add.c	(revision 0)
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=r2 -mcdx" } */
+
+/* Check generation of R2 CDX add.n and addi.n instructions.  */
+
+int f (int a, int b)
+{
+  return a + b;
+}
+
+int g (int a)
+{
+  return a + 32;
+}
+
+int h (int a)
+{
+  return a + 33;
+}
+
+/* { dg-final { scan-assembler "\tadd\\.n\t.*" } } */
+/* { dg-final { scan-assembler "\taddi\\.n\t.*, 32" } } */
+/* { dg-final { scan-assembler "\taddi\t.*, 33" } } */
+
Index: gcc/testsuite/gcc.target/nios2/cdx-branch.c
===================================================================
--- gcc/testsuite/gcc.target/nios2/cdx-branch.c	(revision 0)
+++ gcc/testsuite/gcc.target/nios2/cdx-branch.c	(revision 0)
@@ -0,0 +1,44 @@
+/* { dg-do compile } */
+/* { dg-options "-Os -march=r2 -mcdx" } */
+
+/* Check generation of R2 CDX br.n, beqz.n, bnez.n instructions.  */
+
+int f (int a, int b, int c)
+{
+  if (a == 0)
+    return b;
+  else
+    return c;
+}
+
+int g (int a, int b, int c)
+{
+  if (a != 0)
+    return b;
+  else
+    return c;
+}
+
+extern int i (int);
+extern int j (int);
+extern int k (int);
+
+int h (int a)
+{
+  int x;
+
+  /* As well as the conditional branch for the "if", there has to be
+     an unconditional branch from one branch of the "if" to
+     the return statement.  We compile this testcase with -Os to
+     avoid insertion of a duplicate epilogue in place of the branch.  */
+  if (a == 1)
+    x = i (37);
+  else
+    x = j (42);
+  return x + a + k (x);
+}
+
+/* { dg-final { scan-assembler "\tbeqz\\.n\t.*" } } */
+/* { dg-final { scan-assembler "\tbnez\\.n\t.*" } } */
+/* { dg-final { scan-assembler "\tbeq\t|\tbne\t" } } */
+/* { dg-final { scan-assembler "\tbr\\.n\t.*" } } */
Index: gcc/testsuite/gcc.target/nios2/cdx-callret.c
===================================================================
--- gcc/testsuite/gcc.target/nios2/cdx-callret.c	(revision 0)
+++ gcc/testsuite/gcc.target/nios2/cdx-callret.c	(revision 0)
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=r2 -mcdx" } */
+
+/* Check generation of R2 CDX callr.n, jmpr.n, ret.n instructions.  */
+
+typedef int (*F) (void);
+
+int x (F f)
+{
+  f ();
+
+  /* Note that the compiler might generate a return via pop.n or ldwm;
+     the test below is to make sure that it doesn't generate a 32-bit
+     return instruction.  */
+  return 3;
+}
+
+int y (F f)
+{
+  return f ();
+}
+
+/* { dg-final { scan-assembler "\tcallr\\.n\t.*" } } */
+/* { dg-final { scan-assembler-not "\tret$" } } */
+/* { dg-final { scan-assembler "\tjmpr\\.n\t.*" } } */
Index: gcc/testsuite/gcc.target/nios2/cdx-loadstore.c
===================================================================
--- gcc/testsuite/gcc.target/nios2/cdx-loadstore.c	(revision 0)
+++ gcc/testsuite/gcc.target/nios2/cdx-loadstore.c	(revision 0)
@@ -0,0 +1,61 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=r2 -mcdx" } */
+
+/* Check generation of R2 CDX load/store instructions.  */
+
+unsigned char ldb (unsigned char *p)
+{
+  return p[7];
+}
+
+unsigned short ldh (unsigned short *p)
+{
+  return p[7];
+}
+
+unsigned int ldw (unsigned int *p)
+{
+  return p[7];
+}
+
+void stb (unsigned char *p, unsigned char x)
+{
+  p[15] = x;
+}
+
+void sth (unsigned short *p, unsigned short x)
+{
+  p[15] = x;
+}
+
+void stw (unsigned int *p, unsigned int x)
+{
+  p[15] = x;
+}
+
+void no_cdx_stb (unsigned char *p, unsigned char x)
+{
+  p[16] = x;
+}
+
+void no_cdx_sth (unsigned short *p, unsigned short x)
+{
+  p[16] = x;
+}
+
+void no_cdx_stw (unsigned int *p, unsigned int x)
+{
+  p[16] = x;
+}
+
+/* { dg-final { scan-assembler "\tldbu\\.n\t.*, 7\\(.*\\)" } } */
+/* { dg-final { scan-assembler "\tldhu\\.n\t.*, 14\\(.*\\)" } } */
+/* { dg-final { scan-assembler "\tldw\\.n\t.*, 28\\(.*\\)" } } */
+
+/* { dg-final { scan-assembler "\tstb\\.n\t.*, 15\\(.*\\)" } } */
+/* { dg-final { scan-assembler "\tsth\\.n\t.*, 30\\(.*\\)" } } */
+/* { dg-final { scan-assembler "\tstw\\.n\t.*, 60\\(.*\\)" } } */
+
+/* { dg-final { scan-assembler "\tstb\t.*, 16\\(.*\\)" } } */
+/* { dg-final { scan-assembler "\tsth\t.*, 32\\(.*\\)" } } */
+/* { dg-final { scan-assembler "\tstw\t.*, 64\\(.*\\)" } } */
Index: gcc/testsuite/gcc.target/nios2/cdx-logical.c
===================================================================
--- gcc/testsuite/gcc.target/nios2/cdx-logical.c	(revision 0)
+++ gcc/testsuite/gcc.target/nios2/cdx-logical.c	(revision 0)
@@ -0,0 +1,43 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=r2 -mcdx" } */
+
+/* Check generation of R2 CDX and.n, andi.n, or.n, xor.n, and not.n
+   instructions.
+
+   and.n, or.n, and x.n require one of the input registers to be the same
+   as the output register.  Since the tests below want to put the result
+   in the return value register, they use this function to make sure that
+   one of the input operands is also already in the return register.  */
+
+extern unsigned int x (unsigned int a);
+
+unsigned int f (unsigned int a, unsigned int b)
+{
+  return x (a) & b;
+}
+
+unsigned int g (unsigned int a)
+{
+  return a & 31;
+}
+
+unsigned int h (unsigned int a, unsigned int b)
+{
+  return x (a) | b;
+}
+
+unsigned int i (unsigned int a, unsigned int b)
+{
+  return x (a) ^ b;
+}
+
+unsigned int j (unsigned int a)
+{
+  return ~a;
+}
+
+/* { dg-final { scan-assembler "\tand\\.n\t.*" } } */
+/* { dg-final { scan-assembler "\tandi\\.n\t.*, 31" } } */
+/* { dg-final { scan-assembler "\tor\\.n\t.*" } } */
+/* { dg-final { scan-assembler "\txor\\.n\t.*" } } */
+/* { dg-final { scan-assembler "\tnot\\.n\t.*" } } */
Index: gcc/testsuite/gcc.target/nios2/cdx-mov.c
===================================================================
--- gcc/testsuite/gcc.target/nios2/cdx-mov.c	(revision 0)
+++ gcc/testsuite/gcc.target/nios2/cdx-mov.c	(revision 0)
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=r2 -mcdx" } */
+
+/* Check generation of R2 CDX mov.n and movi.n instructions.  */
+
+extern void f (int a, int b, int c, int d);
+
+int g (int x, int y, int z)
+{
+  f (100, x, y, z);
+  return -1;
+}
+
+/* We should always get mov.n and never mov when compiling with -mcdx.  */
+/* { dg-final { scan-assembler "\tmov\\.n\t.*" } } */
+/* { dg-final { scan-assembler-not "\tmov\t.*" } } */
+
+/* Both of the constant loads are expressible with movi.n.  */
+/* { dg-final { scan-assembler "\tmovi\\.n\t.*, 100" } } */
+/* { dg-final { scan-assembler "\tmovi\\.n\t.*, -1" } } */
Index: gcc/testsuite/gcc.target/nios2/cdx-shift.c
===================================================================
--- gcc/testsuite/gcc.target/nios2/cdx-shift.c	(revision 0)
+++ gcc/testsuite/gcc.target/nios2/cdx-shift.c	(revision 0)
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=r2 -mcdx" } */
+
+/* Check generation of R2 CDX and.n, andi.n, or.n, xor.n, and not.n
+   instructions.  */
+
+extern unsigned int x (unsigned int a);
+
+unsigned int f (unsigned int a, unsigned int b)
+{
+  return x (a) << b;
+}
+
+unsigned int g (unsigned int a)
+{
+  return x (a) << 24;
+}
+
+unsigned int h (unsigned int a, unsigned int b)
+{
+  return x (a) >> b;
+}
+
+unsigned int i (unsigned int a, unsigned int b)
+{
+  return x (a) >> 24;
+}
+
+/* { dg-final { scan-assembler "\tsll\\.n\t.*" } } */
+/* { dg-final { scan-assembler "\tslli\\.n\t.*, 24" } } */
+/* { dg-final { scan-assembler "\tsrl\\.n\t.*" } } */
+/* { dg-final { scan-assembler "\tsrli\\.n\t.*, 24" } } */
Index: gcc/testsuite/gcc.target/nios2/cdx-sub.c
===================================================================
--- gcc/testsuite/gcc.target/nios2/cdx-sub.c	(revision 0)
+++ gcc/testsuite/gcc.target/nios2/cdx-sub.c	(revision 0)
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=r2 -mcdx" } */
+
+/* Check generation of R2 CDX sub.n, subi.n, and neg.n instructions.  */
+
+int f (int a, int b)
+{
+  return a - b;
+}
+
+int g (int a)
+{
+  return a - 32;
+}
+
+int h (int a)
+{
+  return -a;
+}
+
+/* { dg-final { scan-assembler "\tsub\\.n\t.*" } } */
+/* { dg-final { scan-assembler "\tsubi\\.n\t.*, 32" } } */
+/* { dg-final { scan-assembler "\tneg\\.n\t.*" } } */
Index: gcc/testsuite/gcc.target/nios2/nios2-trap-insn.c
===================================================================
--- gcc/testsuite/gcc.target/nios2/nios2-trap-insn.c	(revision 225793)
+++ gcc/testsuite/gcc.target/nios2/nios2-trap-insn.c	(working copy)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-final { scan-assembler "trap\\t3" } } */
+/* { dg-final { scan-assembler "trap\\t3|trap.n\\t3" } } */
 
 /* Test the nios2 trap instruction */
 void foo(void){

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