nios2.h (LABEL_ALIGN): Define.
authorSandra Loosemore <sandra@codesourcery.com>
Tue, 14 Jul 2015 22:56:45 +0000 (18:56 -0400)
committerSandra Loosemore <sandra@gcc.gnu.org>
Tue, 14 Jul 2015 22:56:45 +0000 (18:56 -0400)
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.

Co-Authored-By: Cesar Philippidis <cesar@codesourcery.com>
Co-Authored-By: Chung-Lin Tang <cltang@codesourcery.com>
From-SVN: r225796

20 files changed:
gcc/ChangeLog
gcc/config/nios2/constraints.md
gcc/config/nios2/nios2-protos.h
gcc/config/nios2/nios2.c
gcc/config/nios2/nios2.h
gcc/config/nios2/nios2.md
gcc/config/nios2/predicates.md
gcc/doc/md.texi
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/nios2/andci.c [new file with mode: 0644]
gcc/testsuite/gcc.target/nios2/bmx.c [new file with mode: 0644]
gcc/testsuite/gcc.target/nios2/cdx-add.c [new file with mode: 0644]
gcc/testsuite/gcc.target/nios2/cdx-branch.c [new file with mode: 0644]
gcc/testsuite/gcc.target/nios2/cdx-callret.c [new file with mode: 0644]
gcc/testsuite/gcc.target/nios2/cdx-loadstore.c [new file with mode: 0644]
gcc/testsuite/gcc.target/nios2/cdx-logical.c [new file with mode: 0644]
gcc/testsuite/gcc.target/nios2/cdx-mov.c [new file with mode: 0644]
gcc/testsuite/gcc.target/nios2/cdx-shift.c [new file with mode: 0644]
gcc/testsuite/gcc.target/nios2/cdx-sub.c [new file with mode: 0644]
gcc/testsuite/gcc.target/nios2/nios2-trap-insn.c

index 80b38cd..418a8aa 100644 (file)
@@ -2,6 +2,81 @@
            Cesar Philippidis  <cesar@codesourcery.com>
            Chung-Lin Tang  <cltang@codesourcery.com>
 
+       * 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.
+
+2015-07-14  Sandra Loosemore  <sandra@codesourcery.com>
+           Cesar Philippidis  <cesar@codesourcery.com>
+           Chung-Lin Tang  <cltang@codesourcery.com>
+
        * config/nios2/nios2.h (SMALL_INT12): New macro.
        * config/nios2/nios2.c (nios2_valid_addr_offset_p): New function.
        (nios2_valid_addr_expr_p): Use it.
index 7c7afdf..0ec817f 100644 (file)
 
 ;; 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)
   (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 52985a9..617b6ab 100644 (file)
@@ -42,12 +42,18 @@ extern bool nios2_validate_fpu_compare (machine_mode, rtx *, rtx *, rtx *,
 
 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 93e0a86..d9fe605 100644 (file)
@@ -1195,6 +1195,13 @@ nios2_rtx_costs (rtx x, machine_mode mode ATTRIBUTE_UNUSED,
           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 unspec, rtx tmp)
 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, machine_mode mode)
       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, rtx reg)
 \f
 /* 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, int letter)
       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, int letter)
        }
     }
 
+  /* 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, int letter)
       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, int letter)
 
     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, tree thunk_fndecl ATTRIBUTE_UNUSED,
   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);
+}
+
 \f
 /* Initialize the GCC target structure.  */
 #undef TARGET_ASM_FUNCTION_PROLOGUE
@@ -3549,6 +4210,9 @@ nios2_asm_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
 #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, tree thunk_fndecl ATTRIBUTE_UNUSED,
 #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 58afaec..ff25ade 100644 (file)
@@ -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
 #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 8cf2347..a27df17 100644 (file)
@@ -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
 ; 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
   "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
   "cpu")
 
 (define_insn_reservation "st" 1
-  (eq_attr "type" "st")
+  (eq_attr "type" "st,stwm,push")
   "cpu")
   
 (define_insn_reservation "custom" 1
 
 ; 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
     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])
         (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
 
   ""
   "@
    #
-   ldh%o1\\t%0, %1"
+   ldh%o1%.\\t%0, %1"
   [(set_attr "type" "alu,ld")])
 
 (define_insn "extendqi<mode>2"
   ""
   "@
    #
-   ldb%o1\\t%0, %1"
+   ldb%o1%.\\t%0, %1"
   [(set_attr "type" "alu,ld")])
 
 ;; Split patterns for register alternative cases.
         (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")
   [(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")])
 
 \f
 ;;  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")
         (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")
                      (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")])
+
 
 \f
 ;; Floating point instructions
   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
 (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"
         (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";
   [(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 "" "")
   ""
   "@
    call\\t%0
-   callr\\t%0"
+   callr%.\\t%0"
   [(set_attr "type" "control")])
 
 (define_insn "*call_value"
   ""
   "@
    call\\t%1
-   callr\\t%1"
+   callr%.\\t%1"
   [(set_attr "type" "control")])
 
 (define_expand "sibcall"
   ""
   "@
    jmpi\\t%0
-   jmp\\t%0"
+   jmp%!\\t%0"
   [(set_attr "type" "control")])
 
 (define_insn "sibcall_value_internal"
   ""
   "@
    jmpi\\t%1
-   jmp\\t%1"
+   jmp%!\\t%1"
   [(set_attr "type" "control")])
 
 (define_expand "tablejump"
         (match_operand:SI 0 "register_operand" "c"))
    (use (label_ref (match_operand 1 "" "")))]
   ""
-  "jmp\\t%0"
+  "jmp%!\\t%0"
   [(set_attr "type" "control")])
 
 \f
        (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])
         (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")])
 
 
 (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"
 (define_insn "trap"
   [(trap_if (const_int 1) (const_int 3))]
   ""
-  "trap\\t3"
+  "trap%.\\t3"
   [(set_attr "type" "control")])
 
 (define_insn "ctrapsi4"
                (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 fa57803..ccf3689 100644 (file)
   (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))")))
                                          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 84c39a8..888380e 100644 (file)
@@ -2991,6 +2991,9 @@ instead of @code{0} in the assembly output.
 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 e7a38b5..d090dfc 100644 (file)
@@ -1,3 +1,19 @@
+2015-07-14  Sandra Loosemore  <sandra@codesourcery.com>
+           Cesar Philippidis  <cesar@codesourcery.com>
+           Chung-Lin Tang  <cltang@codesourcery.com>
+
+       * 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.
+
 2015-07-14  Andrea Azzarone  <azzaronea@gmail.com>
 
        PR c++/65071
diff --git a/gcc/testsuite/gcc.target/nios2/andci.c b/gcc/testsuite/gcc.target/nios2/andci.c
new file mode 100644 (file)
index 0000000..98dfb2d
--- /dev/null
@@ -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.*" } }  */
+
diff --git a/gcc/testsuite/gcc.target/nios2/bmx.c b/gcc/testsuite/gcc.target/nios2/bmx.c
new file mode 100644 (file)
index 0000000..9daa606
--- /dev/null
@@ -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" } }  */
diff --git a/gcc/testsuite/gcc.target/nios2/cdx-add.c b/gcc/testsuite/gcc.target/nios2/cdx-add.c
new file mode 100644 (file)
index 0000000..32f1986
--- /dev/null
@@ -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" } } */
+
diff --git a/gcc/testsuite/gcc.target/nios2/cdx-branch.c b/gcc/testsuite/gcc.target/nios2/cdx-branch.c
new file mode 100644 (file)
index 0000000..3b984f2
--- /dev/null
@@ -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.*" } } */
diff --git a/gcc/testsuite/gcc.target/nios2/cdx-callret.c b/gcc/testsuite/gcc.target/nios2/cdx-callret.c
new file mode 100644 (file)
index 0000000..239ec6e
--- /dev/null
@@ -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.*" } } */
diff --git a/gcc/testsuite/gcc.target/nios2/cdx-loadstore.c b/gcc/testsuite/gcc.target/nios2/cdx-loadstore.c
new file mode 100644 (file)
index 0000000..f6a67b9
--- /dev/null
@@ -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\\(.*\\)" } } */
diff --git a/gcc/testsuite/gcc.target/nios2/cdx-logical.c b/gcc/testsuite/gcc.target/nios2/cdx-logical.c
new file mode 100644 (file)
index 0000000..bf3819a
--- /dev/null
@@ -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.*" } } */
diff --git a/gcc/testsuite/gcc.target/nios2/cdx-mov.c b/gcc/testsuite/gcc.target/nios2/cdx-mov.c
new file mode 100644 (file)
index 0000000..000b38b
--- /dev/null
@@ -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" } } */
diff --git a/gcc/testsuite/gcc.target/nios2/cdx-shift.c b/gcc/testsuite/gcc.target/nios2/cdx-shift.c
new file mode 100644 (file)
index 0000000..25bf959
--- /dev/null
@@ -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" } } */
diff --git a/gcc/testsuite/gcc.target/nios2/cdx-sub.c b/gcc/testsuite/gcc.target/nios2/cdx-sub.c
new file mode 100644 (file)
index 0000000..532a0f4
--- /dev/null
@@ -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 3f3900f..588a7f3 100644 (file)
@@ -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){