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]

RFA: MN10300: Add support for LIW instructions


Hi Jeff, Hi Alex,

  Attached is a patch to add support for generating LIW instructions to
  the MN10300 backend.  At the moment the patch does not handle LIWs
  that use immediate values, nor the SETLB and Lcc instructions.  (I
  have saved that support for a later patch).  But it does handle
  register/register LIW instructions and I have tested it without any
  regressions on an mn10300-elf toolchain.

  OK to apply ?

Cheers
  Nick

gcc/ChangeLog
2011-01-27  Nick Clifton  <nickc@redhat.com>

	* config/mn10300/mn10300.opt (mliw): New command line option.
	* config/mn10300/mn10300.md (UNSPEC_LIW): New unspec.
	(liw_bundling): New automaton.
	(liw): New attribute.
	(liw_op): New attribute.
	(liw_op1, liw_op2, liw_both, liw_either): New reservations.
	(movsi_internal): Add LIW attributes.
	(andsi3): Likewise.
	(iorsi3): Likewise.
	(xorsi3): Likewise.
	(addsi3): Separate register and immediate alternatives.
	Add LIW attributes.
	(subsi3): Likewise.
	(cmpsi): Likewise.
	(aslsi3): Likewise.
	(lshrsi3): Likewise.
	(ashrsi3): Likewise.
	(liw): New pattern.
	* config/mn10300/mn10300.c (liw_op_names): New
	(mn10300_print_operand): Handle 'W' operand descriptor.
	(extract_bundle): New function.
	(check_liw_constraints): New function.
	(liw_candidate): New function.
	(mn10300_bundle_liw): New function.
	(mn10300_reorg): New function.
	(TARGET_MACHINE_DEPENDENT_REORG): Define.
	(TARGET_DEFAULT_TARGET_FLAGS): Add MASK_ALLOW_LIW.
	* config/mn10300/mn10300.h (TARGET_CPU_CPP_BUILTINS): Define
	__LIW__ or __NO_LIW__.
	* doc/invoke.texi: Describe the -mliw command line option.

Index: gcc/config/mn10300/mn10300.c
===================================================================
--- gcc/config/mn10300/mn10300.c	(revision 169326)
+++ gcc/config/mn10300/mn10300.c	(working copy)
@@ -165,6 +165,16 @@
     fprintf (asm_out_file, "\t.am33\n");
 }
 
+/* Note: This list must match the liw_op attribute in mn10300.md.  */
+
+static const char *liw_op_names[] =
+{
+  "add", "cmp", "sub", "mov",
+  "and", "or", "xor",
+  "asr", "lsr", "asl",
+  "none", "max"
+};
+
 /* Print operand X using operand code CODE to assembly language output file
    FILE.  */
 
@@ -173,6 +183,18 @@
 {
   switch (code)
     {
+    case 'W':
+      {
+	int ops = INTVAL (x);
+
+	gcc_assert (TARGET_ALLOW_LIW);
+
+	fputs (liw_op_names[ops / LIW_OP_MAX], file);
+	fputc ('_', file);
+	fputs (liw_op_names[ops % LIW_OP_MAX], file);
+	break;
+      }
+
       case 'b':
       case 'B':
 	{
@@ -2923,8 +2947,223 @@
     }
 }
 
+/* Extract operands and (if requested) the LIW op type from the insn.
+   Returns false if the insn can't be bundled.
+   If ops1_post_inc is true, then we require that ops[1] be a POST_INC MEM access.  */
+
+static bool
+extract_bundle (rtx insn, rtx * ops, enum attr_liw_op * plop, bool ops1_post_inc)
+{
+  enum attr_liw_op lop;
+  rtx p, s;
+
+  p = PATTERN (insn);
+  if (GET_CODE (p) == PARALLEL
+      && GET_CODE (XVECEXP (p, 0, 1)) == CLOBBER)
+    p = XVECEXP (p, 0, 0);
+
+  s = SET_SRC (p);
+  lop = get_attr_liw_op (insn);
+  if (plop != NULL)
+    * plop = lop;
+
+  switch (lop)
+    {
+    case LIW_OP_MOV:
+      ops[0] = SET_DEST (p);
+      ops[1] = SET_SRC (p);
+      break;
+    case LIW_OP_CMP:
+      ops[0] = XEXP (SET_SRC (p), 0);
+      ops[1] = XEXP (SET_SRC (p), 1);
+      break;
+    case LIW_OP_NONE:
+      return false;
+    default:
+      ops[0] = SET_DEST (p);
+      ops[1] = XEXP (SET_SRC (p), 1);
+      break;
+    }
+
+  if (ops1_post_inc)
+    {
+      if (GET_CODE (ops[1]) != MEM
+	  || GET_CODE (XEXP (ops[1], 0)) != POST_INC)
+	return false;
+    }
+  else switch (GET_CODE (ops[1]))
+    {
+    case CONST_INT:
+      if (INTVAL (ops[1]) < -4 || INTVAL (ops[1]) > 3)
+	return false;
+      break;
+
+    case REG:
+      break;
+
+    default:
+      return false;
+    }
+
+  return REG_P (ops[0]);
+}
+
+/* Look for conflicts in the registers used in the
+   potential bundling of two insns into one LIW insn.  */
+
+static bool
+check_liw_constraints (rtx ops[4],
+		       enum attr_liw_op op1,
+		       enum attr_liw_op op2,
+		       bool swapped)
+{
+  /* Paranoia check.  */
+  if (! REG_P (ops[0]) || ! REG_P (ops[2]))
+    return false;
+
+  /* Look for the two destination registers being the same.
+     This is OK if the first op is a comparison op, since it
+     will compare the value prior to the completion of the
+     second op.  */
+  if (REGNO (ops[0]) == REGNO (ops[2])
+      && ( (! swapped && op1 != LIW_OP_CMP)
+	  || (swapped && op2 != LIW_OP_CMP)))
+    return false;
+
+  /* Look for the source of the second op
+     being the destination of the first op.  */
+  if (swapped)
+    {
+      if (REG_P (ops[1]) && REGNO (ops[1]) == REGNO (ops[2]))
+	return false;
+    }
+  else if (REG_P (ops[3]) && REGNO (ops[3]) == REGNO (ops[0]))
+    {
+      /* GCC assumes the opcodes are executed sequentially, but the
+	 am33 executes them in parallel.  If the first opcode is a
+	 MOV, we can copy its source to the second ops source.
+	 Otherwise, we just can't combine these.  */
+      if (op1 == LIW_OP_MOV)
+	{
+	  ops[3] = ops[1];
+	  return true;
+	}
+      return false;
+    }
+
+  /* Make sure that only registers are used.  */
+  if (! REG_P (ops[0]) || ! REG_P (ops[1])
+      || ! REG_P (ops[2]) || ! REG_P (ops[3]))
+    return false;
+
+  return true;
+}
+
+/* Decide if the given insn is a candidate for LIW bundling.  For now,
+   we do simple checks.  Later, check operand constraints and such.  */
+
+static bool
+liw_candidate (rtx insn)
+{
+  rtx p;
+
+  if (insn == NULL || ! INSN_P (insn) || DEBUG_INSN_P (insn))
+    return false;
+
+  p = PATTERN (insn);
+  if (GET_CODE (p) == PARALLEL
+      && GET_CODE (XVECEXP (p, 0, 1)) == CLOBBER)
+    p = XVECEXP (p, 0, 0);
+
+  return GET_CODE (p) == SET;
+}
+
+/* Combine pairs of insns into LIW bundles.  */
+
+static void
+mn10300_bundle_liw (void)
+{
+  rtx r, insn1, insn2, ops[4];
+  enum attr_liw liw1, liw2;
+  enum attr_liw_op op1, op2;
+
+  for (r = get_insns (); r; r = NEXT_INSN (r))
+    {
+      bool swapped = false;
+
+      insn1 = r;
+      if (! liw_candidate (insn1))
+	continue;
+
+      insn2 = NEXT_INSN (r);
+      /* Do not let line number notes prevent this optimization,
+	 as otherwise the code produce with "-g" enabled will be different
+	 from the code produced without "-g".  */
+      if (GET_CODE (insn2) == NOTE
+	  && NOTE_KIND (insn2) > 0
+	  && NEXT_INSN (insn2) != NULL)
+	insn2 = NEXT_INSN (insn2);
+
+      if (! liw_candidate (insn2))
+	continue;
+
+      liw1 = get_attr_liw (insn1);
+      if (liw1 == LIW_BOTH)
+	continue;
+      liw2 = get_attr_liw (insn2);
+      if (liw2 == LIW_BOTH)
+	continue;
+      if (liw2 == liw1 && liw1 != LIW_EITHER)
+	continue;
+
+      /* The scheduler always groups the insns correctly, but not
+	 always in sequence.  So, we can do a naive check and expect
+	 it to work.  */
+      if (liw1 == LIW_OP2 || liw2 == LIW_OP1)
+	{
+	  rtx r;
+	  enum attr_liw lt;
+
+	  r = insn1;
+	  insn1 = insn2;
+	  insn2 = r;
+	  lt = liw1;
+	  liw1 = liw2;
+	  liw2 = lt;
+	  swapped = true;
+	}
+
+      if (! extract_bundle (insn1, ops, & op1, false))
+	continue;
+      if (! extract_bundle (insn2, ops + 2, & op2, false))
+	continue;
+      if (! check_liw_constraints (ops, op1, op2, swapped))
+	continue;
+
+      delete_insn (insn2);
+      insn2 = gen_liw (GEN_INT (op1 * LIW_OP_MAX + op2),
+		       ops[0], ops[1], ops[2], ops[3]);
+      insn2 = emit_insn_after (insn2, insn1);
+      delete_insn (insn1);
+      r = insn2;
+    }
+}
+
+static void
+mn10300_reorg (void)
+{
+  if (TARGET_AM33)
+    {
+      if (TARGET_ALLOW_LIW)
+	mn10300_bundle_liw ();
+    }
+}
+
 /* Initialize the GCC target structure.  */
 
+#undef  TARGET_MACHINE_DEPENDENT_REORG
+#define TARGET_MACHINE_DEPENDENT_REORG mn10300_reorg
+
 #undef  TARGET_EXCEPT_UNWIND_INFO
 #define TARGET_EXCEPT_UNWIND_INFO sjlj_except_unwind_info
 
@@ -2952,7 +3191,7 @@
 #define TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA mn10300_asm_output_addr_const_extra
 
 #undef  TARGET_DEFAULT_TARGET_FLAGS
-#define TARGET_DEFAULT_TARGET_FLAGS MASK_MULT_BUG | MASK_PTR_A0D0
+#define TARGET_DEFAULT_TARGET_FLAGS MASK_MULT_BUG | MASK_PTR_A0D0 | MASK_ALLOW_LIW
 #undef  TARGET_HANDLE_OPTION
 #define TARGET_HANDLE_OPTION mn10300_handle_option
 #undef  TARGET_OPTION_OVERRIDE
Index: gcc/config/mn10300/mn10300.opt
===================================================================
--- gcc/config/mn10300/mn10300.opt	(revision 169326)
+++ gcc/config/mn10300/mn10300.opt	(working copy)
@@ -46,3 +46,7 @@
 mreturn-pointer-on-d0
 Target Report Mask(PTR_A0D0)
 Return pointers in both a0 and d0
+
+mliw
+Target Report Mask(ALLOW_LIW)
+Allow gcc to generate LIW instructions
Index: gcc/config/mn10300/mn10300.h
===================================================================
--- gcc/config/mn10300/mn10300.h	(revision 169326)
+++ gcc/config/mn10300/mn10300.h	(working copy)
@@ -50,6 +50,10 @@
         }					\
       else if (TARGET_AM33)			\
         builtin_define ("__AM33__=1");		\
+						\
+      builtin_define (TARGET_ALLOW_LIW ?	\
+		      "__LIW__" : "__NO_LIW__");\
+						\
     }						\
   while (0)
 
Index: gcc/config/mn10300/mn10300.md
===================================================================
--- gcc/config/mn10300/mn10300.md	(revision 169326)
+++ gcc/config/mn10300/mn10300.md	(working copy)
@@ -39,6 +39,9 @@
 
   (UNSPEC_EXT		6)
   (UNSPEC_BSCH		7)
+
+  ;; This is used to encode LIW patterns.
+  (UNSPEC_LIW		8)
 ])
 
 (include "predicates.md")
@@ -75,6 +78,43 @@
 (define_mode_iterator INT [QI HI SI])
 
 
+;; Bundling of smaller insns into a long instruction word (LIW)
+(define_automaton "liw_bundling")
+(automata_option "ndfa")
+
+(define_cpu_unit "liw_op1_u,liw_op2_u" "liw_bundling")
+
+(define_attr "liw" "op1,op2,both,either"
+  (const_string "both"))
+;; Note: this list must match the one defined for liw_op_names[].
+(define_attr "liw_op" "add,cmp,sub,mov,and,or,xor,asr,lsr,asl,none,max"
+  (const_string "none"))
+
+(define_insn_reservation "liw_op1" 1
+  (and (ior (eq_attr "cpu" "am33")
+            (eq_attr "cpu" "am33_2")
+	    (eq_attr "cpu" "am34"))
+       (eq_attr "liw" "op1"))
+  "liw_op1_u");
+(define_insn_reservation "liw_op2" 1
+  (and (ior (eq_attr "cpu" "am33")
+            (eq_attr "cpu" "am33_2")
+	    (eq_attr "cpu" "am34"))
+       (eq_attr "liw" "op2"))
+  "liw_op2_u");
+(define_insn_reservation "liw_both" 1
+  (and (ior (eq_attr "cpu" "am33")
+            (eq_attr "cpu" "am33_2")
+	    (eq_attr "cpu" "am34"))
+       (eq_attr "liw" "both"))
+  "liw_op1_u + liw_op2_u");
+(define_insn_reservation "liw_either" 1
+  (and (ior (eq_attr "cpu" "am33")
+            (eq_attr "cpu" "am33_2")
+	    (eq_attr "cpu" "am34"))
+       (eq_attr "liw" "either"))
+  "liw_op1_u | liw_op2_u");
+
 ;; ----------------------------------------------------------------------
 ;; Pipeline description.
 ;; ----------------------------------------------------------------------
@@ -417,6 +457,8 @@
     }
 }
   [(set_attr "isa" "*,*,*,*,*,*,*,am33,*,*")
+   (set_attr "liw" "*,*,either,*,*,*,*,*,*,*")
+   (set_attr "liw_op" "mov")
    (set_attr_alternative "timings"
 	 [(const_int 11)
 	  (const_int 22)
@@ -521,13 +563,15 @@
 ;; ----------------------------------------------------------------------
 
 (define_insn "addsi3"
-  [(set (match_operand:SI          0 "register_operand"  "=r,!*y,!r")
-	(plus:SI (match_operand:SI 1 "register_operand"  "%0,  0, r")
-		 (match_operand:SI 2 "nonmemory_operand" "ri,  i, r")))
+  [(set (match_operand:SI          0 "register_operand"  "=r,r,!*y,!r")
+	(plus:SI (match_operand:SI 1 "register_operand"  "%0,0,  0, r")
+		 (match_operand:SI 2 "nonmemory_operand"  "r,i,  i, r")))
    (clobber (reg:CC CC_REG))]
   ""
   { return mn10300_output_add (operands, false); }
-  [(set_attr "timings" "11,11,22")]
+  [(set_attr "timings" "11,11,11,22")
+   (set_attr "liw" "either,*,*,*")
+   (set_attr "liw_op" "add")]
 )
 
 ;; Note that ADD IMM,SP does not set the flags, so omit that here.
@@ -714,16 +758,19 @@
 ;; ----------------------------------------------------------------------
 
 (define_insn "subsi3"
-  [(set (match_operand:SI           0 "register_operand"  "=r,r")
-	(minus:SI (match_operand:SI 1 "register_operand"  " 0,r")
-		  (match_operand:SI 2 "nonmemory_operand" "ri,r")))
+  [(set (match_operand:SI           0 "register_operand"  "=r,r,r")
+	(minus:SI (match_operand:SI 1 "register_operand"   "0,0,r")
+		  (match_operand:SI 2 "nonmemory_operand"  "r,i,r")))
    (clobber (reg:CC CC_REG))]
   ""
   "@
    sub %2,%0
+   sub %2,%0
    sub %2,%1,%0"
-  [(set_attr "isa" "*,am33")
-   (set_attr "timings" "11,22")]
+  [(set_attr "isa" "*,*,am33")
+   (set_attr "liw" "either,*,*")
+   (set_attr "liw_op" "sub")
+   (set_attr "timings" "11,11,22")]
 )
 
 (define_insn "*subsi3_flags"
@@ -1125,6 +1172,8 @@
    and %2,%0
    and %2,%1,%0"
   [(set_attr "isa" "*,*,am33")
+   (set_attr "liw" "*,op1,*")
+   (set_attr "liw_op" "and")
    (set_attr "timings" "22,11,11")]
 )
 
@@ -1210,6 +1259,8 @@
    or %2,%0
    or %2,%1,%0"
   [(set_attr "isa" "*,*,am33")
+   (set_attr "liw" "*,op1,*")
+   (set_attr "liw_op" "or")
    (set_attr "timings" "22,11,11")]
 )
 
@@ -1244,6 +1295,8 @@
    xor %2,%0
    xor %2,%1,%0"
   [(set_attr "isa" "*,*,am33")
+   (set_attr "liw" "*,op1,*")
+   (set_attr "liw_op" "xor")
    (set_attr "timings" "22,11,11")]
 )
 
@@ -1321,8 +1374,8 @@
 
 (define_insn "*cmpsi"
   [(set (reg CC_REG)
-	(compare (match_operand:SI 0 "register_operand"  "r")
-		 (match_operand:SI 1 "nonmemory_operand" "ri")))]
+	(compare (match_operand:SI 0 "register_operand"  "r,r")
+		 (match_operand:SI 1 "nonmemory_operand" "r,i")))]
   "reload_completed"
 {
   /* The operands of CMP must be distinct registers.  In the case where
@@ -1336,7 +1389,10 @@
     return "cmp %1,%0";
 }
   [(set_attr_alternative "timings"
-     [(if_then_else (eq_attr "cpu" "am34") (const_int 11) (const_int 22))])]
+     [(if_then_else (eq_attr "cpu" "am34") (const_int 11) (const_int 22))
+      (if_then_else (eq_attr "cpu" "am34") (const_int 11) (const_int 22))])
+   (set_attr "liw" "either,*")
+   (set_attr "liw_op" "cmp")]
 )
 
 (define_insn "*integer_conditional_branch"
@@ -1676,10 +1732,10 @@
 ;; ----------------------------------------------------------------------
 
 (define_insn "ashlsi3"
-  [(set (match_operand:SI  0 "register_operand"  "=r,D,d,d, D,r")
+  [(set (match_operand:SI  0 "register_operand"   "=r,D,d,d,D,D,r")
 	(ashift:SI
-	  (match_operand:SI 1 "register_operand"  " 0,0,0,0, 0,r")
-	  (match_operand:QI 2 "nonmemory_operand" " J,K,M,L,Di,r")))
+	  (match_operand:SI 1 "register_operand"  " 0,0,0,0,0,0,r")
+	  (match_operand:QI 2 "nonmemory_operand" " J,K,M,L,D,i,r")))
    (clobber (reg:CC CC_REG))]
   ""
   "@
@@ -1688,35 +1744,44 @@
    asl2 %0\;add %0,%0
    asl2 %0\;asl2 %0
    asl %S2,%0
+   asl %S2,%0
    asl %2,%1,%0"
-  [(set_attr "isa" "*,*,*,*,*,am33")
-   (set_attr "timings" "11,11,22,22,11,11")]
+  [(set_attr "isa" "*,*,*,*,*,*,am33")
+   (set_attr "liw" "*,*,*,*,op2,*,*")
+   (set_attr "liw_op" "asl")
+   (set_attr "timings" "11,11,22,22,11,11,11")]
 )
 
 (define_insn "lshrsi3"
-  [(set (match_operand:SI  0 "register_operand"  "=D,r")
+  [(set (match_operand:SI  0 "register_operand"  "=D,D,r")
 	(lshiftrt:SI
-	  (match_operand:SI 1 "register_operand"  " 0,r")
-	  (match_operand:QI 2 "nonmemory_operand" "Di,r")))
+	  (match_operand:SI 1 "register_operand"  "0,0,r")
+	  (match_operand:QI 2 "nonmemory_operand" "D,i,r")))
    (clobber (reg:CC CC_REG))]
   ""
   "@
    lsr %S2,%0
+   lsr %S2,%0
    lsr %2,%1,%0"
-  [(set_attr "isa" "*,am33")]
+  [(set_attr "isa" "*,*,am33")
+   (set_attr "liw" "op2,*,*")
+   (set_attr "liw_op" "lsr")]
 )
 
 (define_insn "ashrsi3"
-  [(set (match_operand:SI  0 "register_operand"  "=D,r")
+  [(set (match_operand:SI  0 "register_operand"  "=D,D,r")
 	(ashiftrt:SI
-	  (match_operand:SI 1 "register_operand"  " 0,r")
-	  (match_operand:QI 2 "nonmemory_operand" "Di,r")))
+	  (match_operand:SI 1 "register_operand"  "0,0,r")
+	  (match_operand:QI 2 "nonmemory_operand" "D,i,r")))
    (clobber (reg:CC CC_REG))]
   ""
   "@
    asr %S2,%0
+   asr %S2,%0
    asr %2,%1,%0"
-  [(set_attr "isa" "*,am33")]
+  [(set_attr "isa" "*,*,am33")
+   (set_attr "liw" "op2,*,*")
+   (set_attr "liw_op" "asr")]
 )
 
 ;; ----------------------------------------------------------------------
@@ -2029,3 +2094,16 @@
 }
   [(set_attr "timings" "66")]
 )
+
+(define_insn "liw"
+  [(unspec [(match_operand 0 "" "")
+	    (match_operand 1 "" "")
+	    (match_operand 2 "" "")
+	    (match_operand 3 "" "")
+	    (match_operand 4 "" "")
+	    ] UNSPEC_LIW)]
+  "TARGET_ALLOW_LIW"
+  "%W0 %2, %1, %4, %3"
+  [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
+				       (const_int 13) (const_int 12)))]
+)
Index: gcc/doc/invoke.texi
===================================================================
--- gcc/doc/invoke.texi	(revision 169326)
+++ gcc/doc/invoke.texi	(working copy)
@@ -739,7 +739,7 @@
 -mno-am33 -mam33 -mam33-2 -mam34 @gol
 -mtune=@var{cpu-type} @gol
 -mreturn-pointer-on-d0 @gol
--mno-crt0  -mrelax}
+-mno-crt0  -mrelax -mliw}
 
 @emph{PDP-11 Options}
 @gccoptlist{-mfpu  -msoft-float  -mac0  -mno-ac0  -m40  -m45  -m10 @gol
@@ -15030,6 +15040,19 @@
 has an effect when used on the command line for the final link step.
 
 This option makes symbolic debugging impossible.
+
+@item -mliw
+@opindex mliw
+Allow the compiler to generate @emph{Long Instruction Word}
+instructions if the target is the @samp{AM33} or later.  This is the
+default.  This option defines the preprocessor macro @samp{__LIW__}.
+
+@item -mnoliw
+@opindex mnoliw
+Do not allow the compiler to generate @emph{Long Instruction Word}
+instructions.  This option defines the preprocessor macro
+@samp{__NO_LIW__}.
+
 @end table
 
 @node PDP-11 Options

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