diff mbox

[07/10] gcc/arc: Add nps400 bitops support

Message ID 90a078f4c7d4a8caeacda49886443bcd23f5d25e.1457097757.git.andrew.burgess@embecosm.com
State New
Headers show

Commit Message

Andrew Burgess March 4, 2016, 1:25 p.m. UTC
Add support for nps400 bit operation instructions.  There's a new flag
-mbitops that turns this feature on.  There are new instructions, some
changes to existing instructions, a new register class to support the
new instructions, and some new expand and peephole optimisations.

gcc/ChangeLog:

	* config/arc/arc.c (arc_conditional_register_usage): Take
	TARGET_RRQ_CLASS into account.
	(arc_print_operand): Support printing 'p' and 's' operands.
	* config/arc/arc.h (TARGET_NPS400_BITOPS_DEFAULT): Provide default
	as 0.
	(TARGET_RRQ_CLASS): Define.
	(IS_POWEROF2_OR_0_P): Define.
	* config/arc/arc.md (*movsi_insn): Add w/Clo, w/Chi, and w/Cbi
	alternatives.
	(*tst_movb): New define_insn.
	(*tst): Avoid recognition if it could prevent '*tst_movb'
	combination; replace c/CnL with c/Chs alternative.
	(*tst_bitfield_tst): New define_insn.
	(*tst_bitfield_asr): New define_insn.
	(*tst_bitfield): New define_insn.
	(andsi3_i): Add Rrq variant.
	(extzv): New define_expand.
	(insv): New define_expand.
	(*insv_i): New define_insn.
	(*movb): New define_insn.
	(*movb_signed): New define_insn.
	(*movb_high): New define_insn.
	(*movb_high_signed): New define_insn.
	(*movb_high_signed + 1): New define_split pattern.
	(*mrgb): New define_insn.
	(*mrgb + 1): New define_peephole2 pattern.
	(*mrgb + 2): New define_peephole2 pattern.
	* config/arc/arc.opt (mbitops): New option for nps400, uses
	TARGET_NPS400_BITOPS_DEFAULT.
	* config/arc/constraints.md (q): Make register class conditional.
	(Rrq): New register constraint.
	(Chs): New constraint.
	(Clo): New constraint.
	(Chi): New constraint.
	(Cbf): New constraint.
	(Cbn): New constraint.
	(C18): New constraint.
	(Cbi): New constraint.

gcc/testsuite/ChangeLog:

	* gcc.target/arc/extzv-1.c: New file.
	* gcc.target/arc/insv-1.c: New file.
	* gcc.target/arc/insv-2.c: New file.
	* gcc.target/arc/movb-1.c: New file.
	* gcc.target/arc/movb-2.c: New file.
	* gcc.target/arc/movb-3.c: New file.
	* gcc.target/arc/movb-4.c: New file.
	* gcc.target/arc/movb-5.c: New file.
	* gcc.target/arc/movb_cl-1.c: New file.
	* gcc.target/arc/movb_cl-2.c: New file.
	* gcc.target/arc/movbi_cl-1.c: New file.
	* gcc.target/arc/movl-1.c: New file.
	* gcc.target/arc/mrgb-1.c: New file.
---
 gcc/ChangeLog.NPS400                      |  42 ++++
 gcc/config/arc/arc.c                      |  33 ++-
 gcc/config/arc/arc.h                      |   9 +
 gcc/config/arc/arc.md                     | 382 ++++++++++++++++++++++++++----
 gcc/config/arc/arc.opt                    |   4 +
 gcc/config/arc/constraints.md             |  58 ++++-
 gcc/testsuite/ChangeLog.NPS400            |  17 ++
 gcc/testsuite/gcc.target/arc/extzv-1.c    |  11 +
 gcc/testsuite/gcc.target/arc/insv-1.c     |  21 ++
 gcc/testsuite/gcc.target/arc/insv-2.c     |  18 ++
 gcc/testsuite/gcc.target/arc/movb-1.c     |  13 +
 gcc/testsuite/gcc.target/arc/movb-2.c     |  13 +
 gcc/testsuite/gcc.target/arc/movb-3.c     |  13 +
 gcc/testsuite/gcc.target/arc/movb-4.c     |  13 +
 gcc/testsuite/gcc.target/arc/movb-5.c     |  13 +
 gcc/testsuite/gcc.target/arc/movb_cl-1.c  |   9 +
 gcc/testsuite/gcc.target/arc/movb_cl-2.c  |  11 +
 gcc/testsuite/gcc.target/arc/movbi_cl-1.c |   9 +
 gcc/testsuite/gcc.target/arc/movl-1.c     |  17 ++
 gcc/testsuite/gcc.target/arc/mrgb-1.c     |  14 ++
 20 files changed, 663 insertions(+), 57 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/arc/extzv-1.c
 create mode 100644 gcc/testsuite/gcc.target/arc/insv-1.c
 create mode 100644 gcc/testsuite/gcc.target/arc/insv-2.c
 create mode 100644 gcc/testsuite/gcc.target/arc/movb-1.c
 create mode 100644 gcc/testsuite/gcc.target/arc/movb-2.c
 create mode 100644 gcc/testsuite/gcc.target/arc/movb-3.c
 create mode 100644 gcc/testsuite/gcc.target/arc/movb-4.c
 create mode 100644 gcc/testsuite/gcc.target/arc/movb-5.c
 create mode 100644 gcc/testsuite/gcc.target/arc/movb_cl-1.c
 create mode 100644 gcc/testsuite/gcc.target/arc/movb_cl-2.c
 create mode 100644 gcc/testsuite/gcc.target/arc/movbi_cl-1.c
 create mode 100644 gcc/testsuite/gcc.target/arc/movl-1.c
 create mode 100644 gcc/testsuite/gcc.target/arc/mrgb-1.c
diff mbox

Patch

diff --git a/gcc/ChangeLog.NPS400 b/gcc/ChangeLog.NPS400
index 2a0f820..8229d67 100644
--- a/gcc/ChangeLog.NPS400
+++ b/gcc/ChangeLog.NPS400
@@ -1,3 +1,45 @@ 
+2013-02-19  Joern Rennecke  <joern.rennecke@embecosm.com>
+	    Andrew Burgess  <andrew.burgess@embecosm.com>
+
+	* config/arc/arc.c (arc_conditional_register_usage): Take
+	TARGET_RRQ_CLASS into account.
+	(arc_print_operand): Support printing 'p' and 's' operands.
+	* config/arc/arc.h (TARGET_NPS400_BITOPS_DEFAULT): Provide default
+	as 0.
+	(TARGET_RRQ_CLASS): Define.
+	(IS_POWEROF2_OR_0_P): Define.
+	* config/arc/arc.md (*movsi_insn): Add w/Clo, w/Chi, and w/Cbi
+	alternatives.
+	(*tst_movb): New define_insn.
+	(*tst): Avoid recognition if it could prevent '*tst_movb'
+	combination; replace c/CnL with c/Chs alternative.
+	(*tst_bitfield_tst): New define_insn.
+	(*tst_bitfield_asr): New define_insn.
+	(*tst_bitfield): New define_insn.
+	(andsi3_i): Add Rrq variant.
+	(extzv): New define_expand.
+	(insv): New define_expand.
+	(*insv_i): New define_insn.
+	(*movb): New define_insn.
+	(*movb_signed): New define_insn.
+	(*movb_high): New define_insn.
+	(*movb_high_signed): New define_insn.
+	(*movb_high_signed + 1): New define_split pattern.
+	(*mrgb): New define_insn.
+	(*mrgb + 1): New define_peephole2 pattern.
+	(*mrgb + 2): New define_peephole2 pattern.
+	* config/arc/arc.opt (mbitops): New option for nps400, uses
+	TARGET_NPS400_BITOPS_DEFAULT.
+	* config/arc/constraints.md (q): Make register class conditional.
+	(Rrq): New register constraint.
+	(Chs): New constraint.
+	(Clo): New constraint.
+	(Chi): New constraint.
+	(Cbf): New constraint.
+	(Cbn): New constraint.
+	(C18): New constraint.
+	(Cbi): New constraint.
+
 2013-08-31  Joern Rennecke  <joern.rennecke@embecosm.com>
 	    Andrew Burgess  <andrew.burgess@embecosm.com>
 
diff --git a/gcc/config/arc/arc.c b/gcc/config/arc/arc.c
index 25ff693..a75f200 100644
--- a/gcc/config/arc/arc.c
+++ b/gcc/config/arc/arc.c
@@ -1371,7 +1371,8 @@  arc_conditional_register_usage (void)
     {
       if (i < 29)
 	{
-	  if (TARGET_Q_CLASS && ((i <= 3) || ((i >= 12) && (i <= 15))))
+	  if ((TARGET_Q_CLASS || TARGET_RRQ_CLASS)
+	      && ((i <= 3) || ((i >= 12) && (i <= 15))))
 	    arc_regno_reg_class[i] = ARCOMPACT16_REGS;
 	  else
 	    arc_regno_reg_class[i] = GENERAL_REGS;
@@ -1388,12 +1389,12 @@  arc_conditional_register_usage (void)
 	arc_regno_reg_class[i] = NO_REGS;
     }
 
-  /* ARCOMPACT16_REGS is empty, if TARGET_Q_CLASS has not been activated.  */
+  /* ARCOMPACT16_REGS is empty, if TARGET_Q_CLASS / TARGET_RRQ_CLASS
+     has not been activated.  */
+  if (!TARGET_Q_CLASS && !TARGET_RRQ_CLASS)
+    CLEAR_HARD_REG_SET(reg_class_contents [ARCOMPACT16_REGS]);
   if (!TARGET_Q_CLASS)
-    {
-      CLEAR_HARD_REG_SET(reg_class_contents [ARCOMPACT16_REGS]);
-      CLEAR_HARD_REG_SET(reg_class_contents [AC16_BASE_REGS]);
-    }
+    CLEAR_HARD_REG_SET(reg_class_contents [AC16_BASE_REGS]);
 
   gcc_assert (FIRST_PSEUDO_REGISTER >= 144);
 
@@ -2935,6 +2936,8 @@  static int output_scaled = 0;
     'Z': log2(x+1)-1
     'z': log2
     'M': log2(~x)
+    'p': bit Position of lsb
+    's': size of bit field
     '#': condbranch delay slot suffix
     '*': jump delay slot suffix
     '?' : nonjump-insn suffix for conditional execution or short instruction
@@ -2985,6 +2988,24 @@  arc_print_operand (FILE *file, rtx x, int code)
 
       return;
 
+    case 'p':
+      if (GET_CODE (x) == CONST_INT)
+	fprintf (file, "%d", exact_log2 (INTVAL (x) & -INTVAL (x)));
+      else
+	output_operand_lossage ("invalid operand to %%p code");
+      return;
+
+    case 's':
+      if (GET_CODE (x) == CONST_INT)
+	{
+	  HOST_WIDE_INT i = INTVAL (x);
+	  HOST_WIDE_INT s = exact_log2 (i & -i);
+	  fprintf (file, "%d", exact_log2 (((0xffffffffUL & i) >> s) + 1));
+	}
+      else
+	output_operand_lossage ("invalid operand to %%s code");
+      return;
+
     case '#' :
       /* Conditional branches depending on condition codes.
 	 Note that this is only for branches that were known to depend on
diff --git a/gcc/config/arc/arc.h b/gcc/config/arc/arc.h
index 28c3ef1..f278bf5 100644
--- a/gcc/config/arc/arc.h
+++ b/gcc/config/arc/arc.h
@@ -318,10 +318,18 @@  along with GCC; see the file COPYING3.  If not see
 #define UNALIGNED_ACCESS_DEFAULT 0
 #endif
 
+#ifndef TARGET_NPS400_BITOPS_DEFAULT
+#define TARGET_NPS400_BITOPS_DEFAULT 0
+#endif
+
 #ifndef TARGET_NPS400_CMEM_DEFAULT
 #define TARGET_NPS400_CMEM_DEFAULT 0
 #endif
 
+/* Enable the RRQ instruction alternatives.  */
+
+#define TARGET_RRQ_CLASS TARGET_NPS400_BITOPS
+
 /* Target machine storage layout.  */
 
 /* We want zero_extract to mean the same
@@ -1025,6 +1033,7 @@  extern int arc_initial_elimination_offset(int from, int to);
 
 /* Is the argument a const_int rtx, containing an exact power of 2 */
 #define  IS_POWEROF2_P(X) (! ( (X) & ((X) - 1)) && (X))
+#define  IS_POWEROF2_OR_0_P(X) (! ( (X) & ((X) - 1)))
 
 /* The macros REG_OK_FOR..._P assume that the arg is a REG rtx
    and check its validity for a certain class.
diff --git a/gcc/config/arc/arc.md b/gcc/config/arc/arc.md
index 33e6dee..e318fc8 100644
--- a/gcc/config/arc/arc.md
+++ b/gcc/config/arc/arc.md
@@ -691,8 +691,8 @@ 
 ; insns it should lengthen the return insn.
 ; N.B. operand 1 of alternative 7 expands into pcl,symbol@gotpc .
 (define_insn "*movsi_insn"
-  [(set (match_operand:SI 0 "move_dest_operand" "=Rcq,Rcq#q,w, w,w,  w,???w, ?w,  w,Rcq#q, w,Rcq,  S,Us<,RcqRck,!*x,r,r,Ucm,m,???m,VUsc")
-	(match_operand:SI 1 "move_src_operand"  " cL,cP,Rcq#q,cL,I,Crr,?Rac,Cpc,Clb,?Cal,?Cal,T,Rcq,RcqRck,Us>,Usd,Ucm,m,w,c,?Rac,C32"))]
+  [(set (match_operand:SI 0 "move_dest_operand" "=Rcq,Rcq#q,w,w,w,w,w,w,w,???w,?w,w,Rcq#q,w,Rcq,S,Us<,RcqRck,!*x,r,r,Ucm,m,???m,VUsc")
+	(match_operand:SI 1 "move_src_operand"  "cL,cP,Rcq#q,cL,I,Crr,Clo,Chi,Cbi,?Rac,Cpc,Clb,?Cal,?Cal,T,Rcq,RcqRck,Us>,Usd,Ucm,m,w,c,?Rac,C32"))]
   "register_operand (operands[0], SImode)
    || register_operand (operands[1], SImode)
    || (CONSTANT_P (operands[1])
@@ -707,29 +707,32 @@ 
    mov%? %0,%1		;3
    mov%? %0,%1		;4
    ror %0,((%1*2+1) & 0x3f) ;5
-   mov%? %0,%1		;6
-   add %0,%S1		;7
+   movl.cl %0,%1       ;6
+   movh.cl %0,%L1>>16  ;7
+   * return INTVAL (operands[1]) & 0xffffff ? \"movbi.cl %0,%1 >> %p1,%p1,8;8\" : \"movbi.cl %0,%L1 >> 24,24,8;9\";
+   mov%? %0,%1		;9
+   add %0,%S1		;10
    * return arc_get_unalign () ? \"add %0,pcl,%1-.+2\" : \"add %0,pcl,%1-.\";
-   mov%? %0,%S1%&	;9
-   mov%? %0,%S1		;10
-   ld%? %0,%1%&		;11
-   st%? %1,%0%&		;12
+   mov%? %0,%S1%&	;12
+   mov%? %0,%S1		;13
+   ld%? %0,%1%&		;14
+   st%? %1,%0%&		;15
    * return arc_short_long (insn, \"push%? %1%&\", \"st%U0 %1,%0%&\");
    * return arc_short_long (insn, \"pop%? %0%&\",  \"ld%U1 %0,%1%&\");
-   ld%? %0,%1%&		;15
-   xld%U1 %0,%1         ;16
-   ld%U1%V1 %0,%1	;17
-   xst%U0 %1,%0         ;18
-   st%U0%V0 %1,%0       ;19
-   st%U0%V0 %1,%0       ;20
-   st%U0%V0 %S1,%0      ;21"
-  [(set_attr "type" "move,move,move,move,move,two_cycle_core,move,binary,binary,move,move,load,store,store,load,load,load,load,store,store,store,store")
-   (set_attr "iscompact" "maybe,maybe,maybe,false,false,false,false,false,false,maybe_limm,false,true,true,true,true,true,false,false,false,false,false,false")
+   ld%? %0,%1%&		;18
+   xld%U1 %0,%1                ;19
+   ld%U1%V1 %0,%1	;20
+   xst%U0 %1,%0                ;21
+   st%U0%V0 %1,%0       ;22
+   st%U0%V0 %1,%0       ;23
+   st%U0%V0 %S1,%0      ;24"
+  [(set_attr "type" "move,move,move,move,move,two_cycle_core,shift,shift,shift,move,binary,binary,move,move,load,store,store,load,load,load,load,store,store,store,store")
+   (set_attr "iscompact" "maybe,maybe,maybe,false,false,false,false,false,false,false,false,false,maybe_limm,false,true,true,true,true,true,false,false,false,false,false,false")
    ; Use default length for iscompact to allow for COND_EXEC.  But set length
    ; of Crr to 4.
-   (set_attr "length" "*,*,*,4,4,4,4,8,8,*,8,*,*,*,*,*,4,*,4,*,*,8")
-   (set_attr "predicable" "yes,no,yes,yes,no,no,yes,no,no,yes,yes,no,no,no,no,no,no,no,no,no,no,no")
-   (set_attr "cpu_facility" "*,*,av1,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*")])
+   (set_attr "length" "*,*,*,4,4,4,4,4,4,4,8,8,*,8,*,*,*,*,*,4,*,4,*,*,8")
+   (set_attr "predicable" "yes,no,yes,yes,no,no,no,no,no,yes,no,no,yes,yes,no,no,no,no,no,no,no,no,no,no,no")
+   (set_attr "cpu_facility" "*,*,av1,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*")])
 
 ;; Sometimes generated by the epilogue code.  We don't want to
 ;; recognize these addresses in general, because the limm is costly,
@@ -800,6 +803,24 @@ 
    (set_attr "cond" "set_zn")
    (set_attr "length" "4")])
 
+; reload is too stingy with reloads for Rrq/Cbf/Rrq when it sees
+; a c/???Cal/X alternative, so we say it's c/???Cal/c instead,
+; even if we don't need the clobber.
+(define_insn_and_split "*tst_movb"
+  [(set
+     (match_operand 0 "cc_register" "")
+     (match_operator 4 "zn_compare_operator"
+       [(and:SI
+	  (match_operand:SI 1 "register_operand"  "%Rcq,Rcq, c,  c,  c,  c,Rrq,  3,  c")
+	  (match_operand:SI 2 "nonmemory_operand"  "Rcq,C0p,cI,C1p,Ccp,Chs,Cbf,Cbf,???Cal"))
+	(const_int 0)]))
+   (clobber (match_scratch:SI 3 "=X,X,X,X,X,X,Rrq,Rrq,c"))]
+  "TARGET_NPS400_BITOPS"
+  "movb.f.cl %3,%1,%p2,%p2,%s2"
+  "reload_completed
+   && (extract_constrain_insn_cached (insn), (which_alternative & ~1) != 6)"
+  [(set (match_dup 0) (match_dup 4))])
+
 (define_insn "*tst"
   [(set
      (match_operand 0 "cc_register" "")
@@ -808,12 +829,14 @@ 
 	  (match_operand:SI 1 "register_operand"
 	   "%Rcq,Rcq, c, c, c,  c,  c,  c")
 	  (match_operand:SI 2 "nonmemory_operand"
-	   " Rcq,C0p,cI,cL,C1p,Ccp,CnL,Cal"))
+	   " Rcq,C0p,cI,cL,C1p,Ccp,Chs,Cal"))
 	(const_int 0)]))]
-  "(register_operand (operands[1], SImode)
-    && nonmemory_operand (operands[2], SImode))
-   || (memory_operand (operands[1], SImode)
-       && satisfies_constraint_Cux (operands[2]))"
+  "reload_completed
+   || !satisfies_constraint_Cbf (operands[2])
+   || satisfies_constraint_C0p (operands[2])
+   || satisfies_constraint_I (operands[2])
+   || satisfies_constraint_C1p (operands[2])
+   || satisfies_constraint_Chs (operands[2])"
   "*
     switch (which_alternative)
     {
@@ -826,17 +849,79 @@ 
     case 5:
       return \"bclr%?.f 0,%1,%M2%&\";
     case 6:
-      return \"bic%?.f 0,%1,%n2-1\";
+      return \"asr.f 0,%1,%p2\";
     default:
       gcc_unreachable ();
     }
   "
   [(set_attr "iscompact" "maybe,maybe,false,false,false,false,false,false")
-   (set_attr "type" "compare")
+   (set_attr "type" "compare,compare,compare,compare,compare,compare,shift,compare")
    (set_attr "length" "*,*,4,4,4,4,4,8")
    (set_attr "predicable" "no,yes,no,yes,no,no,no,yes")
    (set_attr "cond" "set_zn")])
 
+; ??? Sometimes, if an AND with a constant can be expressed as a zero_extract,
+; combine will do that and not try the AND.
+
+; It would take 66 constraint combinations to describe the zero_extract
+; constants that are covered by the 12-bit signed constant for tst
+; (excluding the ones that are better done by mov or btst).
+; so we rather use an extra pattern for tst;
+; since this is about constants, reload shouldn't care.
+(define_insn "*tst_bitfield_tst"
+  [(set (match_operand:CC_ZN 0 "cc_set_register" "")
+	(match_operator 4 "zn_compare_operator"
+	  [(zero_extract:SI
+	     (match_operand:SI 1 "register_operand"  "c")
+	     (match_operand:SI 2 "const_int_operand" "n")
+	     (match_operand:SI 3 "const_int_operand" "n"))
+	   (const_int 0)]))]
+  "INTVAL (operands[2]) > 1
+   && (INTVAL (operands[3]) + INTVAL (operands[2]) <= 11
+       || (INTVAL (operands[3]) <= 11
+	   && INTVAL (operands[3]) + INTVAL (operands[2]) == 32))"
+  "tst %1,(1<<%2)-1<<%3"
+  [(set_attr "type" "compare")
+   (set_attr "cond" "set_zn")
+   (set_attr "length" "4")])
+
+; Likewise for asr.f.
+(define_insn "*tst_bitfield_asr"
+  [(set (match_operand:CC_ZN 0 "cc_set_register" "")
+	(match_operator 4 "zn_compare_operator"
+	  [(zero_extract:SI
+	     (match_operand:SI 1 "register_operand"  "c")
+	     (match_operand:SI 2 "const_int_operand" "n")
+	     (match_operand:SI 3 "const_int_operand" "n"))
+	   (const_int 0)]))]
+  "INTVAL (operands[2]) > 1
+   && INTVAL (operands[3]) + INTVAL (operands[2]) == 32"
+  "asr.f 0,%1,%3"
+  [(set_attr "type" "shift")
+   (set_attr "cond" "set_zn")
+   (set_attr "length" "4")])
+
+(define_insn "*tst_bitfield"
+  [(set (match_operand:CC_ZN 0 "cc_set_register" "")
+	(match_operator 5 "zn_compare_operator"
+	  [(zero_extract:SI
+	     (match_operand:SI 1 "register_operand" "%Rcqq,c,  c,Rrq,c")
+	     (match_operand:SI 2 "const_int_operand"    "N,N,  n,Cbn,n")
+	     (match_operand:SI 3 "const_int_operand"    "n,n,C_0,Cbn,n"))
+	   (const_int 0)]))
+   (clobber (match_scratch:SI 4 "=X,X,X,Rrq,X"))]
+  ""
+  "@
+   btst%? %1,%3
+   btst %1,%3
+   bmsk.f 0,%1,%2-1
+   movb.f.cl %4,%1,%3,%3,%2
+   and.f 0,%1,((1<<%2)-1)<<%3"
+  [(set_attr "iscompact" "maybe,false,false,false,false")
+   (set_attr "type" "compare,compare,compare,shift,compare")
+   (set_attr "cond" "set_zn")
+   (set_attr "length" "*,4,4,4,8")])
+
 (define_insn "*commutative_binary_comparison"
   [(set (match_operand:CC_ZN 0 "cc_set_register" "")
 	(match_operator:CC_ZN 5 "zn_compare_operator"
@@ -2947,30 +3032,40 @@ 
      operands[1] = arc_rewrite_small_data (operands[1]);")
 
 (define_insn "andsi3_i"
-  [(set (match_operand:SI 0 "dest_reg_operand"          "=Rcqq,Rcq,Rcqq,Rcqq,Rcqq,Rcw,Rcw,Rcw,Rcw,Rcw,Rcw,  w,  w,  w,  w,w,Rcw,  w,  W")
-	(and:SI (match_operand:SI 1 "nonimmediate_operand" "%0,Rcq,   0,   0,Rcqq,  0,  c,  0,  0,  0,  0,  c,  c,  c,  c,0,  0,  c,  o")
-		(match_operand:SI 2 "nonmemory_operand" " Rcqq,  0, C1p, Ccp, Cux, cL,  0,C1p,Ccp,CnL,  I, Lc,C1p,Ccp,CnL,I,Cal,Cal,Cux")))]
+  [(set (match_operand:SI 0 "dest_reg_operand" "=Rcqq,Rcq,Rcqq,Rcqq,Rcqq,Rcw,Rcw,Rcw,Rcw,Rcw,Rcw,w,w,w,w,Rrq,w,Rcw,w,W")
+	(and:SI (match_operand:SI 1 "nonimmediate_operand" "%0,Rcq,0,0,Rcqq,0,c,0,0,0,0,c,c,c,c,Rrq,0,0,c,o")
+		(match_operand:SI 2 "nonmemory_operand" "Rcqq,0,C1p,Ccp,Cux,cL,0,C1p,Ccp,CnL,I,Lc,C1p,Ccp,CnL,Cbf,I,Cal,Cal,Cux")))]
   "(register_operand (operands[1], SImode)
     && nonmemory_operand (operands[2], SImode))
    || (memory_operand (operands[1], SImode)
        && satisfies_constraint_Cux (operands[2]))"
-  "*
 {
   switch (which_alternative)
     {
-    case 0: case 5: case 10: case 11: case 15: case 16: case 17:
-      return \"and%? %0,%1,%2%&\";
+    case 0: case 5: case 10: case 11: case 16: case 17: case 18:
+      return "and%? %0,%1,%2%&";
     case 1: case 6:
-      return \"and%? %0,%2,%1%&\";
+      return "and%? %0,%2,%1%&";
     case 2: case 7: case 12:
-      return \"bmsk%? %0,%1,%Z2%&\";
+      return "bmsk%? %0,%1,%Z2%&";
     case 3: case 8: case 13:
-      return \"bclr%? %0,%1,%M2%&\";
+      return "bclr%? %0,%1,%M2%&";
     case 4:
       return (INTVAL (operands[2]) == 0xff
-	      ? \"extb%? %0,%1%&\" : \"ext%_%? %0,%1%&\");
+	      ? "extb%? %0,%1%&" : "ext%_%? %0,%1%&");
     case 9: case 14: return \"bic%? %0,%1,%n2-1\";
-    case 18:
+    case 15:
+      return "movb.cl %0,%1,%p2,%p2,%s2";
+
+    case 19:
+      const char *tmpl;
+
+      if (satisfies_constraint_Ucm (operands[1]))
+	tmpl = (INTVAL (operands[2]) == 0xff
+		? "xldb%U1 %0,%1" : "xld%_%U1 %0,%1");
+      else
+	tmpl = INTVAL (operands[2]) == 0xff ? "ldb %0,%1" : "ld%_ %0,%1";
+
       if (TARGET_BIG_ENDIAN)
 	{
 	  rtx xop[2];
@@ -2978,21 +3073,19 @@ 
 	  xop[0] = operands[0];
 	  xop[1] = adjust_address (operands[1], QImode,
 				   INTVAL (operands[2]) == 0xff ? 3 : 2);
-	  output_asm_insn (INTVAL (operands[2]) == 0xff
-			   ? \"ldb %0,%1\" : \"ld%_ %0,%1\",
-			   xop);
-	  return \"\";
+	  output_asm_insn (tmpl, xop);
+	  return "";
 	}
-      return INTVAL (operands[2]) == 0xff ? \"ldb %0,%1\" : \"ld%_ %0,%1\";
+      return tmpl;
     default:
       gcc_unreachable ();
     }
-}"
-  [(set_attr "iscompact" "maybe,maybe,maybe,maybe,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false")
-   (set_attr "type" "binary,binary,binary,binary,binary,binary,binary,binary,binary,binary,binary,binary,binary,binary,binary,binary,binary,binary,load")
-   (set_attr "length" "*,*,*,*,*,4,4,4,4,4,4,4,4,4,4,4,8,8,*")
-   (set_attr "predicable" "no,no,no,no,no,yes,yes,yes,yes,yes,no,no,no,no,no,no,yes,no,no")
-   (set_attr "cond" "canuse,canuse,canuse,canuse,nocond,canuse,canuse,canuse,canuse,canuse,canuse_limm,nocond,nocond,nocond,nocond,canuse_limm,canuse,nocond,nocond")])
+}
+  [(set_attr "iscompact" "maybe,maybe,maybe,maybe,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false")
+   (set_attr "type" "binary,binary,binary,binary,binary,binary,binary,binary,binary,binary,binary,binary,binary,binary,binary,shift,binary,binary,binary,load")
+   (set_attr "length" "*,*,*,*,*,4,4,4,4,4,4,4,4,4,4,4,4,8,8,*")
+   (set_attr "predicable" "no,no,no,no,no,yes,yes,yes,yes,yes,no,no,no,no,no,no,no,yes,no,no")
+   (set_attr "cond" "canuse,canuse,canuse,canuse,nocond,canuse,canuse,canuse,canuse,canuse,canuse_limm,nocond,nocond,nocond,nocond,nocond,canuse_limm,canuse,nocond,nocond")])
 
 ; combiner splitter, pattern found in ldtoa.c .
 ; and op3,op0,op1 / cmp op3,op2 -> add op3,op0,op4 / bmsk.f 0,op3,op1
@@ -5642,7 +5735,6 @@ 
   [(set_attr "length" "4")
    (set_attr "type" "misc")])
 
-
 ;; FPU/FPX expands
 
 ;;add
@@ -5785,6 +5877,196 @@ 
    gcc_unreachable ();
  ")
 
+(define_expand "extzv"
+  [(set (match_operand:SI 0 "register_operand" "")
+	(zero_extract:SI (match_operand:SI 1 "register_operand" "")
+			 (match_operand:SI 2 "const_int_operand" "")
+			 (match_operand:SI 3 "const_int_operand" "")))]
+  "TARGET_NPS400_BITOPS")
+
+; We need a sanity check in the instuction predicate because combine
+; will throw any old rubbish at us and see what sticks.
+(define_insn "*extzv_i"
+  [(set (match_operand:SI 0 "register_operand" "=Rrq")
+	(zero_extract:SI (match_operand:SI 1 "register_operand" "Rrq")
+			 (match_operand:SI 2 "const_int_operand" "n")
+			 (match_operand:SI 3 "const_int_operand" "n")))]
+  "TARGET_NPS400_BITOPS && INTVAL (operands[2]) + INTVAL (operands[3]) <= 32"
+  "movb.cl %0,%1,0,%3,%2"
+  [(set_attr "type" "shift")
+   (set_attr "length" "4")])
+
+(define_expand "insv"
+  [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "")
+			 (match_operand:SI 1 "const_int_operand" "")
+			 (match_operand:SI 2 "const_int_operand" ""))
+	(match_operand:SI 3 "nonmemory_operand" ""))]
+  "TARGET_NPS400_BITOPS"
+{
+  int size = INTVAL (operands[1]);
+
+  if (size != 1 && size != 2 && size != 4 && size != 8)
+    operands[3] = force_reg (SImode, operands[3]);
+})
+
+(define_insn "*insv_i"
+  [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+w,Rrq")
+			 (match_operand:SI 1 "const_int_operand" "C18,n")
+			 (match_operand:SI 2 "const_int_operand" "n,n"))
+	(match_operand:SI 3 "nonmemory_operand" "P,Rrq"))]
+  "TARGET_NPS400_BITOPS
+   && (register_operand (operands[3], SImode)
+       || satisfies_constraint_C18 (operands[1]))"
+  "@
+   movbi %0,%0,%3,%2,%1
+   movb %0,%0,%3,%2,0,%1"
+  [(set_attr "type" "shift")
+   (set_attr "length" "4")])
+
+(define_insn "*movb"
+  [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+Rrq")
+			 (match_operand:SI 1 "const_int_operand" "n")
+			 (match_operand:SI 2 "const_int_operand" "n"))
+	(zero_extract:SI (match_operand:SI 3 "register_operand" "Rrq")
+			 (match_dup 1)
+			 (match_operand:SI 4 "const_int_operand" "n")))]
+  "TARGET_NPS400_BITOPS"
+  "movb %0,%0,%3,%2,%4,%1"
+  [(set_attr "type" "shift")
+   (set_attr "length" "4")])
+
+(define_insn "*movb_signed"
+  [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+Rrq")
+			 (match_operand:SI 1 "const_int_operand" "n")
+			 (match_operand:SI 2 "const_int_operand" "n"))
+	(sign_extract:SI (match_operand:SI 3 "register_operand" "Rrq")
+			 (match_dup 1)
+			 (match_operand:SI 4 "const_int_operand" "n")))]
+  "TARGET_NPS400_BITOPS"
+  "movb %0,%0,%3,%2,%4,%1"
+  [(set_attr "type" "shift")
+   (set_attr "length" "4")])
+
+(define_insn "*movb_high"
+  [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+Rrq")
+			 (match_operand:SI 1 "const_int_operand" "n")
+			 (match_operand:SI 2 "const_int_operand" "n"))
+	(lshiftrt:SI (match_operand:SI 3 "register_operand" "Rrq")
+		     (match_operand:SI 4 "const_int_operand" "n")))]
+  "TARGET_NPS400_BITOPS
+   && INTVAL (operands[4]) + INTVAL (operands[1]) <= 32"
+  "movb %0,%0,%3,%2,%4,%1"
+  [(set_attr "type" "shift")
+   (set_attr "length" "4")])
+
+; N.B.: when processing signed bitfields that fit in the top half of
+; a word, gcc will use a narrow sign extending load, and in this case
+; we will see INTVAL (operands[4]) + INTVAL (operands[1]) == 16 (or 8)
+(define_insn "*movb_high_signed"
+  [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+Rrq")
+			 (match_operand:SI 1 "const_int_operand" "n")
+			 (match_operand:SI 2 "const_int_operand" "n"))
+	(ashiftrt:SI (match_operand:SI 3 "register_operand" "Rrq")
+		     (match_operand:SI 4 "const_int_operand" "n")))]
+  "TARGET_NPS400_BITOPS
+   && INTVAL (operands[4]) + INTVAL (operands[1]) <= 32"
+  "movb %0,%0,%3,%2,%4,%1"
+  [(set_attr "type" "shift")
+   (set_attr "length" "4")])
+
+(define_split
+  [(set (match_operand:SI 0 "register_operand" "")
+	(ior:SI (ashift:SI (match_operand:SI 1 "register_operand" "")
+			   (match_operand:SI 2 "const_int_operand" ""))
+		(subreg:SI (match_operand 3 "") 0)))]
+  "TARGET_NPS400_BITOPS
+   && GET_MODE_BITSIZE (GET_MODE (operands[3])) <= INTVAL (operands[2])
+   && !reg_overlap_mentioned_p (operands[0], operands[1])"
+  [(set (match_dup 0) (zero_extend:SI (match_dup 3)))
+   (set (zero_extract:SI (match_dup 0) (match_dup 4) (match_dup 2))
+	(match_dup 1))]
+  "operands[4] = GEN_INT (32 - INTVAL (operands[2]));")
+
+(define_insn "*mrgb"
+  [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+Rrq")
+			 (match_operand:SI 1 "const_int_operand" "n")
+			 (match_operand:SI 2 "const_int_operand" "n"))
+	(zero_extract:SI (match_dup 0) (match_dup 1)
+			 (match_operand:SI 3 "const_int_operand" "n")))
+   (set (zero_extract:SI (match_dup 0)
+			 (match_operand:SI 4 "const_int_operand" "n")
+			 (match_operand:SI 5 "const_int_operand" "n"))
+	(zero_extract:SI (match_operand:SI 6 "register_operand" "Rrq")
+			 (match_dup 4)
+			 (match_operand:SI 7 "const_int_operand" "n")))]
+  "TARGET_NPS400_BITOPS"
+{
+  output_asm_insn ("mrgb %0,%0,%6,%2,%3,%1,%5,%7,%4", operands);
+  /* The ;%? updates the known unalignment.  */
+  return arc_short_long (insn, ";%?", "nop_s");
+}
+  [(set_attr "type" "shift")
+   (set_attr "length" "6")
+   (set_attr "iscompact" "true")])
+
+;; combine fumbles combination of two movb patterns, and then the
+;; combination is rejected by combinable_i3pat.
+;; Thus, we can only use a peephole2 to combine two such insns.
+
+(define_peephole2
+  [(set (match_operand:SI 0 "register_operand" "")
+	(match_operand:SI 1 "register_operand" ""))
+   (set (zero_extract:SI (match_dup 0)
+			 (match_operand:SI 2 "const_int_operand" "")
+			 (match_operand:SI 3 "const_int_operand" ""))
+	(zero_extract:SI (match_dup 1)
+			 (match_dup 2)
+			 (match_operand:SI 4 "const_int_operand" "")))
+   (match_operand 9) ; unrelated insn scheduled here
+   (set (zero_extract:SI (match_dup 0)
+			 (match_operand:SI 5 "const_int_operand" "")
+			 (match_operand:SI 6 "const_int_operand" ""))
+	(zero_extract:SI (match_operand:SI 7 "register_operand" "")
+			 (match_dup 5)
+			 (match_operand:SI 8 "const_int_operand" "")))]
+  "TARGET_NPS400_BITOPS
+   // Check that the second movb doesn't clobber an input of the extra insn.
+   && !reg_overlap_mentioned_p (operands[0], operands[9])
+   // And vice versa.
+   && !reg_set_p (operands[0], operands[9])
+   && !reg_set_p (operands[7], operands[9])"
+  [(set (match_dup 0) (match_dup 1))
+   (parallel [(set (zero_extract:SI (match_dup 0) (match_dup 1) (match_dup 2))
+		   (zero_extract:SI (match_dup 3) (match_dup 1) (match_dup 4)))
+	      (set (zero_extract:SI (match_dup 0) (match_dup 1) (match_dup 2))
+		   (zero_extract:SI (match_dup 3) (match_dup 1) (match_dup 4)))])
+   (match_dup 9)])
+
+(define_peephole2
+  [(set (match_operand:SI 0 "register_operand" "")
+	(match_operand:SI 1 "register_operand" ""))
+   (set (zero_extract:SI (match_dup 0)
+			 (match_operand:SI 2 "const_int_operand" "")
+			 (match_operand:SI 3 "const_int_operand" ""))
+	(zero_extract:SI (match_dup 1)
+			 (match_dup 2)
+			 (match_operand:SI 4 "const_int_operand" "")))
+   (set (match_dup 1) (match_operand 8))
+   (set (zero_extract:SI (match_dup 0)
+			 (match_operand:SI 5 "const_int_operand" "")
+			 (match_operand:SI 6 "const_int_operand" ""))
+	(zero_extract:SI (match_dup 1) (match_dup 5)
+			 (match_operand:SI 7 "const_int_operand" "")))]
+  "TARGET_NPS400_BITOPS
+   && !reg_overlap_mentioned_p (operands[0], operands[8])"
+  [(set (match_dup 0) (match_dup 1))
+   (set (match_dup 1) (match_dup 8))
+   (parallel [(set (zero_extract:SI (match_dup 0) (match_dup 2) (match_dup 3))
+		   (zero_extract:SI (match_dup 0) (match_dup 2) (match_dup 4)))
+	      (set (zero_extract:SI (match_dup 0) (match_dup 5) (match_dup 6))
+		   (zero_extract:SI (match_dup 1) (match_dup 5) (match_dup 7)))])
+   (match_dup 1)])
+
 ;; include the arc-FPX instructions
 (include "fpx.md")
 
diff --git a/gcc/config/arc/arc.opt b/gcc/config/arc/arc.opt
index 4816238..3411599 100644
--- a/gcc/config/arc/arc.opt
+++ b/gcc/config/arc/arc.opt
@@ -457,6 +457,10 @@  Enum(arc_fpu) String(fpus_all) Value(FPU_SP | FPU_SC | FPU_SF | FPU_SD)
 EnumValue
 Enum(arc_fpu) String(fpud_all) Value(FPU_SP | FPU_SC | FPU_SF | FPU_SD | FPU_DP | FPU_DC | FPU_DF | FPU_DD)
 
+mbitops
+Target Report Var(TARGET_NPS400_BITOPS) Init(TARGET_NPS400_BITOPS_DEFAULT) Condition(ARC_NPS400)
+Enable use of NPS400 bit operations.
+
 mcmem
 Target Report Var(TARGET_NPS400_CMEM) Init(TARGET_NPS400_CMEM_DEFAULT) Condition(ARC_NPS400)
 Enable use of NPS400 xld/xst extension.
diff --git a/gcc/config/arc/constraints.md b/gcc/config/arc/constraints.md
index 409e7d6..37370dd 100644
--- a/gcc/config/arc/constraints.md
+++ b/gcc/config/arc/constraints.md
@@ -66,10 +66,18 @@ 
    Link Registers @code{ilink1}:@code{r29}, @code{ilink2}:@code{r30},
    @code{blink}:@code{r31},")
 
-(define_register_constraint "q" "ARCOMPACT16_REGS"
+(define_register_constraint "q" "TARGET_Q_CLASS ? ARCOMPACT16_REGS : NO_REGS"
   "Registers usable in ARCompact 16-bit instructions: @code{r0}-@code{r3},
    @code{r12}-@code{r15}")
 
+; NPS400 bitfield instructions require registers from the r0-r3,r12-r15
+; range, and thus we need a register class and constraint that works
+; independently of size optimization.
+(define_register_constraint
+ "Rrq" "TARGET_RRQ_CLASS ? ARCOMPACT16_REGS : NO_REGS"
+  "Registers usable in NPS400 bitfield instructions: @code{r0}-@code{r3},
+   @code{r12}-@code{r15}")
+
 (define_register_constraint "e" "AC16_BASE_REGS"
   "Registers usable as base-regs of memory addresses in ARCompact 16-bit memory
    instructions: @code{r0}-@code{r3}, @code{r12}-@code{r15}, @code{sp}")
@@ -236,12 +244,60 @@ 
   (and (match_code "const_int")
        (match_test "ival == 0xff || ival == 0xffff")))
 
+(define_constraint "Chs"
+ "@internal
+  constant for a highpart that can be checked with a shift (asr.f 0,rn,m)"
+  (and (match_code "const_int")
+       (match_test "IS_POWEROF2_P (-ival)")))
+
+(define_constraint "Clo"
+ "@internal
+  constant that fits into 16 lower bits, for movl"
+  (and (match_code "const_int")
+       (match_test "TARGET_NPS400_BITOPS")
+       (match_test "(ival & ~0xffffU) == 0")))
+
+(define_constraint "Chi"
+ "@internal
+  constant that fits into 16 higher bits, for movh_i"
+  (and (match_code "const_int")
+       (match_test "TARGET_NPS400_BITOPS")
+       (match_test "trunc_int_for_mode (ival >> 16, HImode) << 16 == ival")))
+
+(define_constraint "Cbf"
+ "@internal
+  a mask for a bit field, for AND using movb_i"
+  (and (match_code "const_int")
+       (match_test "TARGET_NPS400_BITOPS")
+       (match_test "IS_POWEROF2_OR_0_P (ival + (ival & -ival))")))
+
+(define_constraint "Cbn"
+ "@internal
+  a constant integer, valid only if TARGET_NPS400_BITOPS is true"
+  (and (match_code "const_int")
+       (match_test "TARGET_NPS400_BITOPS")))
+
+(define_constraint "C18"
+ "@internal
+  1,2,4 or 8"
+  (and (match_code "const_int")
+       (match_test "ival == 1 || ival == 2 || ival == 4 || ival == 8")))
+
 (define_constraint "Crr"
  "@internal
   constant that can be loaded with ror b,u6"
   (and (match_code "const_int")
        (match_test "(ival & ~0x8000001f) == 0 && !arc_ccfsm_cond_exec_p ()")))
 
+(define_constraint "Cbi"
+ "@internal
+  constant that can be loaded with movbi.cl"
+  (and (match_code "const_int")
+       (match_test "TARGET_NPS400_BITOPS")
+       (match_test "!ival
+		    || ((ival & 0xffffffffUL) >> exact_log2 (ival & -ival)
+			<= 0xff)")))
+
 ;; Floating-point constraints
 
 (define_constraint "G"
diff --git a/gcc/testsuite/ChangeLog.NPS400 b/gcc/testsuite/ChangeLog.NPS400
index bc5e68c..22dec32 100644
--- a/gcc/testsuite/ChangeLog.NPS400
+++ b/gcc/testsuite/ChangeLog.NPS400
@@ -1,3 +1,20 @@ 
+2013-02-19  Joern Rennecke  <joern.rennecke@embecosm.com>
+	    Andrew Burgess  <andrew.burgess@embecosm.com>
+
+	* gcc.target/arc/extzv-1.c: New file.
+	* gcc.target/arc/insv-1.c: New file.
+	* gcc.target/arc/insv-2.c: New file.
+	* gcc.target/arc/movb-1.c: New file.
+	* gcc.target/arc/movb-2.c: New file.
+	* gcc.target/arc/movb-3.c: New file.
+	* gcc.target/arc/movb-4.c: New file.
+	* gcc.target/arc/movb-5.c: New file.
+	* gcc.target/arc/movb_cl-1.c: New file.
+	* gcc.target/arc/movb_cl-2.c: New file.
+	* gcc.target/arc/movbi_cl-1.c: New file.
+	* gcc.target/arc/movl-1.c: New file.
+	* gcc.target/arc/mrgb-1.c: New file.
+
 2013-08-09  Joern Rennecke  <joern.rennecke@embecosm.com>
 	    Andrew Burgess  <andrew.burgess@embecosm.com>
 
diff --git a/gcc/testsuite/gcc.target/arc/extzv-1.c b/gcc/testsuite/gcc.target/arc/extzv-1.c
new file mode 100644
index 0000000..465a377
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/extzv-1.c
@@ -0,0 +1,11 @@ 
+/* { dg-do compile { target arc*-mellanox-* } } */
+/* { dg-options "-O2 -mbitops" } */
+
+struct foo { unsigned a: 3, b: 5, c: 24; };
+
+int
+f (struct foo i)
+{
+  return i.b;
+}
+/* { dg-final { scan-assembler "movb\.cl" } } */
diff --git a/gcc/testsuite/gcc.target/arc/insv-1.c b/gcc/testsuite/gcc.target/arc/insv-1.c
new file mode 100644
index 0000000..cbba28e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/insv-1.c
@@ -0,0 +1,21 @@ 
+/* { dg-do compile { target arc*-mellanox-* } } */
+/* { dg-options "-O2 -mbitops" } */
+
+/* ??? Irrespective of insn set, generated code for this is a mess.  */
+struct foo { unsigned a: 3, b: 8, c: 21; };
+
+struct foo
+f (struct foo i)
+{
+  i.b = 42;
+  return i;
+}
+
+struct foo
+g (struct foo i, int j)
+{
+  i.b = j;
+  return i;
+}
+/* { dg-final { scan-assembler "movbi\[ \t\]" } } */
+/* { dg-final { scan-assembler "movb\[ \t\]" } } */
diff --git a/gcc/testsuite/gcc.target/arc/insv-2.c b/gcc/testsuite/gcc.target/arc/insv-2.c
new file mode 100644
index 0000000..7c468b3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/insv-2.c
@@ -0,0 +1,18 @@ 
+/* { dg-do compile { target arc*-mellanox-* } } */
+/* { dg-options "-O2 -mbitops" } */
+
+struct foo { unsigned a: 3, b: 8, c: 21; } bar;
+
+void
+f (void)
+{
+  bar.b = 42;
+}
+
+void
+g (int j)
+{
+  bar.b = j;
+}
+/* { dg-final { scan-assembler "movbi\[ \t\]" } } */
+/* { dg-final { scan-assembler "movb\[ \t\]" } } */
diff --git a/gcc/testsuite/gcc.target/arc/movb-1.c b/gcc/testsuite/gcc.target/arc/movb-1.c
new file mode 100644
index 0000000..bcd9ea3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/movb-1.c
@@ -0,0 +1,13 @@ 
+/* { dg-do compile { target arc*-mellanox-* } } */
+/* { dg-options "-O2 -mbitops" } */
+
+struct { unsigned a: 5, b: 8, c: 19; } foo;
+struct { unsigned a: 3, b: 8, c: 21; } bar;
+
+void
+f (void)
+{
+  bar.b = foo.b;
+}
+/* { dg-final { scan-assembler "movb\[ \t\]+r\[0-5\]+, *r\[0-5\]+, *r\[0-5\]+, *5, *3, *8" { target arceb-*-* } } } */
+/* { dg-final { scan-assembler "movb\[ \t\]+r\[0-5\]+, *r\[0-5\]+, *r\[0-5\]+, *19, *21, *8" { target arc-*-* } } } */
diff --git a/gcc/testsuite/gcc.target/arc/movb-2.c b/gcc/testsuite/gcc.target/arc/movb-2.c
new file mode 100644
index 0000000..5d1aac8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/movb-2.c
@@ -0,0 +1,13 @@ 
+/* { dg-do compile { target arc*-mellanox-* } } */
+/* { dg-options "-O2 -mbitops" } */
+
+struct { unsigned a: 23, b: 9; } foo;
+struct { unsigned a: 23, b: 9; } bar;
+
+void
+f (void)
+{
+  bar.b = foo.b;
+}
+/* { dg-final { scan-assembler "movb\[ \t\]+r\[0-5\]+, *r\[0-5\]+, *r\[0-5\]+, *23, *23, *9" { target arc-*-* } } } */
+/* { dg-final { scan-assembler "movb\[ \t\]+r\[0-5\]+, *r\[0-5\]+, *r\[0-5\]+, *0, *0, *9" { target arceb-*-* } } } */
diff --git a/gcc/testsuite/gcc.target/arc/movb-3.c b/gcc/testsuite/gcc.target/arc/movb-3.c
new file mode 100644
index 0000000..77cac4a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/movb-3.c
@@ -0,0 +1,13 @@ 
+/* { dg-do compile { target arc*-mellanox-* } } */
+/* { dg-options "-O2 -mbitops" } */
+
+struct { int a: 23, b: 9; } foo;
+struct { int a: 23, b: 9; } bar;
+
+void
+f (void)
+{
+  bar.a = foo.a;
+}
+/* { dg-final { scan-assembler "movb\[ \t\]+r\[0-5\]+, *r\[0-5\]+, *r\[0-5\]+, *0, *0, *23" { target arc-*-* } } } */
+/* { dg-final { scan-assembler "movb\[ \t\]+r\[0-5\]+, *r\[0-5\]+, *r\[0-5\]+, *9, *9, *23" { target arceb-*-* } } } */
diff --git a/gcc/testsuite/gcc.target/arc/movb-4.c b/gcc/testsuite/gcc.target/arc/movb-4.c
new file mode 100644
index 0000000..c45e35a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/movb-4.c
@@ -0,0 +1,13 @@ 
+/* { dg-do compile { target arc*-mellanox-* } } */
+/* { dg-options "-O2 -mbitops" } */
+
+struct { int a: 13, b: 19; } foo;
+struct { int a: 13, b: 19; } bar;
+
+void
+f (void)
+{
+  bar.b = foo.b;
+}
+/* { dg-final { scan-assembler "movb\[ \t\]+r\[0-5\]+, *r\[0-5\]+, *r\[0-5\]+, *13, *13, *19" { target arc-*-* } } } */
+/* { dg-final { scan-assembler "movb\[ \t\]+r\[0-5\]+, *r\[0-5\]+, *r\[0-5\]+, *0, *0, *19" { target arceb-*-* } } } */
diff --git a/gcc/testsuite/gcc.target/arc/movb-5.c b/gcc/testsuite/gcc.target/arc/movb-5.c
new file mode 100644
index 0000000..6de13ae
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/movb-5.c
@@ -0,0 +1,13 @@ 
+/* { dg-do compile { target arc*-mellanox-* } } */
+/* { dg-options "-O2 -mbitops" } */
+
+struct { int a: 23, b: 9; } foo;
+struct { int a: 23, b: 9; } bar;
+
+void
+f (void)
+{
+  bar.b = foo.b;
+}
+/* { dg-final { scan-assembler "movb\[ \t\]+r\[0-5\]+, *r\[0-5\]+, *r\[0-5\]+, *23, *(23|7), *9" { target arc-*-* } } } */
+/* { dg-final { scan-assembler "movb\[ \t\]+r\[0-5\]+, *r\[0-5\]+, *r\[0-5\]+, *0, *0, *9" { target arceb-*-* } } } */
diff --git a/gcc/testsuite/gcc.target/arc/movb_cl-1.c b/gcc/testsuite/gcc.target/arc/movb_cl-1.c
new file mode 100644
index 0000000..7d2c388
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/movb_cl-1.c
@@ -0,0 +1,9 @@ 
+/* { dg-do compile { target arc*-mellanox-* } } */
+/* { dg-options "-O2 -mbitops" } */
+
+int
+f (int i)
+{
+  return i & 0x0ffff000;
+}
+/* { dg-final { scan-assembler "movb\.cl" } } */
diff --git a/gcc/testsuite/gcc.target/arc/movb_cl-2.c b/gcc/testsuite/gcc.target/arc/movb_cl-2.c
new file mode 100644
index 0000000..21df97b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/movb_cl-2.c
@@ -0,0 +1,11 @@ 
+/* { dg-do compile { target arc*-mellanox-* } } */
+/* { dg-options "-O2 -mbitops" } */
+
+extern void g (void);
+int
+f (int i)
+{
+  if (i & 0x0ffff000)
+    g ();
+}
+/* { dg-final { scan-assembler "movb\.f\.cl" } } */
diff --git a/gcc/testsuite/gcc.target/arc/movbi_cl-1.c b/gcc/testsuite/gcc.target/arc/movbi_cl-1.c
new file mode 100644
index 0000000..af74b22
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/movbi_cl-1.c
@@ -0,0 +1,9 @@ 
+/* { dg-do compile { target arc*-mellanox-* } } */
+/* { dg-options "-O2 -mbitops" } */
+
+int
+f (int i)
+{
+  return 0x6e00;
+}
+/* { dg-final { scan-assembler "mov(bi|l)\.cl" } } */
diff --git a/gcc/testsuite/gcc.target/arc/movl-1.c b/gcc/testsuite/gcc.target/arc/movl-1.c
new file mode 100644
index 0000000..f4f810a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/movl-1.c
@@ -0,0 +1,17 @@ 
+/* { dg-do compile { target arc*-mellanox-* } } */
+/* { dg-options "-O2 -mbitops" } */
+
+int
+f (void)
+{
+  return 0xd00d;
+}
+
+int
+g (void)
+{
+  return 0x7ff00000;
+}
+
+/* { dg-final { scan-assembler "movl\.cl\[ \t\]" } } */
+/* { dg-final { scan-assembler "movh\.cl\[ \t\]" } } */
diff --git a/gcc/testsuite/gcc.target/arc/mrgb-1.c b/gcc/testsuite/gcc.target/arc/mrgb-1.c
new file mode 100644
index 0000000..11c9fe2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/mrgb-1.c
@@ -0,0 +1,14 @@ 
+/* { dg-do compile { target arc*-mellanox-* } } */
+/* { dg-options "-O2 -mbitops" } */
+
+struct { unsigned a: 5, b: 8, c: 8, d: 11; } foo;
+struct { unsigned a: 3, b: 8, c: 21; } bar;
+
+void
+f (void)
+{
+  foo.b = foo.c;
+  foo.c = bar.b;
+}
+/* { dg-final { scan-assembler "mrgb\[ \t\]+r\[0-5\]+, *r\[0-5\]+, *r\[0-5\]+, *5, *13, *8, *13, *3, *8" { target arc-*-* } } } */
+/* { dg-final { scan-assembler "mrgb\[ \t\]+r\[0-5\]+, *r\[0-5\]+, *r\[0-5\]+, *19, *11, *8, *11, *21, *8" { target arceb-*-* } } } */