OSDN Git Service

2005-12-08 Andreas Krebbel <krebbel1@de.ibm.com>
[pf3gnuchains/gcc-fork.git] / gcc / config / s390 / s390.md
index e4d7097..c9ce6fd 100644 (file)
 ;;     %C: print opcode suffix for branch condition.
 ;;     %D: print opcode suffix for inverse branch condition.
 ;;     %J: print tls_load/tls_gdcall/tls_ldcall suffix
+;;     %G: print the size of the operand in bytes.
 ;;     %O: print only the displacement of a memory reference.
 ;;     %R: print only the base register of a memory reference.
 ;;     %S: print S-type memory reference (base+displacement).
 ;;     %N: print the second word of a DImode operand.
 ;;     %M: print the second word of a TImode operand.
-
+;;     %Y: print shift count operand.
+;;  
 ;;     %b: print integer X as if it's an unsigned byte.
-;;     %x: print integer X as if it's an unsigned word.
-;;     %h: print integer X as if it's a signed word.
-;;     %i: print the first nonzero HImode part of X
-;;     %j: print the first HImode part unequal to 0xffff of X
-
+;;     %x: print integer X as if it's an unsigned halfword.
+;;     %h: print integer X as if it's a signed halfword.
+;;     %i: print the first nonzero HImode part of X.
+;;     %j: print the first HImode part unequal to -1 of X.
+;;     %k: print the first nonzero SImode part of X.
+;;     %m: print the first SImode part unequal to -1 of X.
+;;     %o: print integer X as if it's an unsigned 32bit word.
 ;;
 ;; We have a special constraint for pattern matching.
 ;;
   [; Miscellaneous
    (UNSPEC_ROUND               1)
    (UNSPEC_CMPINT              2)
-   (UNSPEC_SETHIGH             10)
+   (UNSPEC_ICM                 10)
 
    ; GOT/PLT and lt-relative accesses
    (UNSPEC_LTREL_OFFSET                100)
 
    ; String Functions
    (UNSPEC_SRST                        600)
+   (UNSPEC_MVST                        601)
    
    ; Stack Smashing Protector
    (UNSPEC_SP_SET              700)
 ;; same template.
 (define_mode_macro FPR     [DF SF])
 
+;; These mode macros allow 31-bit and 64-bit TDSI patterns to be generated
+;; from the same template.
+(define_mode_macro TDSI [(TI "TARGET_64BIT") DI SI])
+
 ;; These mode macros allow 31-bit and 64-bit GPR patterns to be generated
 ;; from the same template.
 (define_mode_macro GPR [(DI "TARGET_64BIT") SI])
 
 ;; This mode macro allows :P to be used for patterns that operate on
 ;; pointer-sized quantities.  Exactly one of the two alternatives will match.
+(define_mode_macro DP  [(TI "TARGET_64BIT") (DI "!TARGET_64BIT")])
 (define_mode_macro P [(DI "TARGET_64BIT") (SI "!TARGET_64BIT")])
 
 ;; This mode macro allows the QI and HI patterns to be defined from
 ;; the same template.
 (define_code_macro SHIFT [ashift lshiftrt])
 
+;; These macros allow to combine most atomic operations.
+(define_code_macro ATOMIC [and ior xor plus minus mult])
+(define_code_attr atomic [(and "and") (ior "ior") (xor "xor") 
+                         (plus "add") (minus "sub") (mult "nand")])
+
 
 ;; In FPR templates, a string like "lt<de>br" will expand to "ltdbr" in DFmode
 ;; and "ltebr" in SFmode.
 ;; in "RRE" for DImode and "RR" for SImode.
 (define_mode_attr E [(DI "E") (SI "")])
 
+;; This attribute handles differences in the instruction 'type' and will result
+;; in "RSE" for TImode and "RS" for DImode.
+(define_mode_attr TE [(TI "E") (DI "")])
+
 ;; In GPR templates, a string like "lc<g>r" will expand to "lcgr" in DImode
 ;; and "lcr" in SImode.
 (define_mode_attr g [(DI "g") (SI "")])
 
+;; In DP templates, a string like "cds<g>" will expand to "cdsg" in TImode
+;; and "cds" in DImode.
+(define_mode_attr tg [(TI "g") (DI "")])
+
 ;; In GPR templates, a string like "c<gf>dbr" will expand to "cgdbr" in DImode
 ;; and "cfdbr" in SImode.
 (define_mode_attr gf [(DI "g") (SI "f")])
 
-;; ICM mask required to load MODE value into the highest subreg
-;; of a SImode register.
-(define_mode_attr icm_hi [(HI "12") (QI "8")])
-
 ;; ICM mask required to load MODE value into the lowest subreg
 ;; of a SImode register.
 (define_mode_attr icm_lo [(HI "3") (QI "1")])
      (use (match_operand 5 "const_int_operand" ""))])]
   "s390_offset_p (operands[0], operands[3], operands[2])
    && s390_offset_p (operands[1], operands[4], operands[2])
+   && !s390_overlap_p (operands[0], operands[1], 
+                       INTVAL (operands[2]) + INTVAL (operands[5]))
    && INTVAL (operands[2]) + INTVAL (operands[5]) <= 256"
   [(parallel
     [(set (match_dup 6) (match_dup 7))
    (set_attr "type" "vs")])
  
 ;
+; movstr instruction pattern.
+;
+
+(define_expand "movstr"
+  [(set (reg:SI 0) (const_int 0))
+   (parallel 
+    [(clobber (match_dup 3))
+     (set (match_operand:BLK 1 "memory_operand" "")
+         (match_operand:BLK 2 "memory_operand" ""))
+     (set (match_operand 0 "register_operand" "")
+         (unspec [(match_dup 1) 
+                  (match_dup 2)
+                  (reg:SI 0)] UNSPEC_MVST))
+     (clobber (reg:CC CC_REGNUM))])]
+  ""
+{
+  rtx addr1 = gen_reg_rtx (Pmode);
+  rtx addr2 = gen_reg_rtx (Pmode);
+
+  emit_move_insn (addr1, force_operand (XEXP (operands[1], 0), NULL_RTX));
+  emit_move_insn (addr2, force_operand (XEXP (operands[2], 0), NULL_RTX));
+  operands[1] = replace_equiv_address_nv (operands[1], addr1);
+  operands[2] = replace_equiv_address_nv (operands[2], addr2);
+  operands[3] = addr2;
+})
+
+(define_insn "*movstr"
+  [(clobber (match_operand:P 2 "register_operand" "=d"))
+   (set (mem:BLK (match_operand:P 1 "register_operand" "0"))
+       (mem:BLK (match_operand:P 3 "register_operand" "2")))
+   (set (match_operand:P 0 "register_operand" "=d")
+       (unspec [(mem:BLK (match_dup 1)) 
+                (mem:BLK (match_dup 3))
+                (reg:SI 0)] UNSPEC_MVST))
+   (clobber (reg:CC CC_REGNUM))]
+  ""
+  "mvst\t%1,%2\;jo\t.-4"
+  [(set_attr "length" "8")
+   (set_attr "type" "vs")])
+  
+
+;
 ; movmemM instruction pattern(s).
 ;
 
   [(parallel
     [(clobber (match_dup 1))
      (set (match_operand:BLK 0 "memory_operand" "")
-          (match_operand 2 "setmem_operand" ""))
+          (match_operand 2 "shift_count_or_setmem_operand" ""))
      (use (match_operand 1 "general_operand" ""))
      (use (match_dup 3))
      (clobber (reg:CC CC_REGNUM))])]
 (define_insn "*setmem_long"
   [(clobber (match_operand:<DBL> 0 "register_operand" "=d"))
    (set (mem:BLK (subreg:P (match_operand:<DBL> 3 "register_operand" "0") 0))
-        (match_operand 2 "setmem_operand" "Y"))
+        (match_operand 2 "shift_count_or_setmem_operand" "Y"))
    (use (match_dup 3))
    (use (match_operand:<DBL> 1 "register_operand" "d"))
    (clobber (reg:CC CC_REGNUM))]
   [(set_attr "length" "8")
    (set_attr "type" "vs")])
 
+(define_insn "*setmem_long_and"
+  [(clobber (match_operand:<DBL> 0 "register_operand" "=d"))
+   (set (mem:BLK (subreg:P (match_operand:<DBL> 3 "register_operand" "0") 0))
+        (and (match_operand 2 "shift_count_or_setmem_operand" "Y")
+            (match_operand 4 "const_int_operand"             "n")))
+   (use (match_dup 3))
+   (use (match_operand:<DBL> 1 "register_operand" "d"))
+   (clobber (reg:CC CC_REGNUM))]
+  "(INTVAL (operands[4]) & 255) == 255"
+  "mvcle\t%0,%1,%Y2\;jo\t.-4"
+  [(set_attr "length" "8")
+   (set_attr "type" "vs")])
 ;
 ; cmpmemM instruction pattern(s).
 ;
 ;;- Conversion instructions.
 ;;
 
-
-(define_insn "*sethigh<mode>si"
+(define_insn "*sethighpartsi"
   [(set (match_operand:SI 0 "register_operand" "=d,d")
-        (unspec:SI [(match_operand:HQI 1 "s_operand" "Q,S")] UNSPEC_SETHIGH))
+       (unspec:SI [(match_operand:BLK 1 "s_operand" "Q,S")
+                   (match_operand 2 "const_int_operand" "n,n")] UNSPEC_ICM))
    (clobber (reg:CC CC_REGNUM))]
   ""
   "@
-   icm\t%0,<icm_hi>,%S1
-   icmy\t%0,<icm_hi>,%S1"
+   icm\t%0,%2,%S1
+   icmy\t%0,%2,%S1"
   [(set_attr "op_type" "RS,RSY")])
 
-(define_insn "*sethighqidi_64"
+(define_insn "*sethighpartdi_64"
   [(set (match_operand:DI 0 "register_operand" "=d")
-        (unspec:DI [(match_operand:QI 1 "s_operand" "QS")] UNSPEC_SETHIGH))
+       (unspec:DI [(match_operand:BLK 1 "s_operand" "QS")
+                   (match_operand 2 "const_int_operand" "n")] UNSPEC_ICM))
    (clobber (reg:CC CC_REGNUM))]
   "TARGET_64BIT"
-  "icmh\t%0,8,%S1"
+  "icmh\t%0,%2,%S1"
   [(set_attr "op_type" "RSY")])
 
-(define_insn "*sethighqidi_31"
+(define_insn "*sethighpartdi_31"
   [(set (match_operand:DI 0 "register_operand" "=d,d")
-        (unspec:DI [(match_operand:QI 1 "s_operand" "Q,S")] UNSPEC_SETHIGH))
+       (unspec:DI [(match_operand:BLK 1 "s_operand" "Q,S")
+                   (match_operand 2 "const_int_operand" "n,n")] UNSPEC_ICM))
    (clobber (reg:CC CC_REGNUM))]
   "!TARGET_64BIT"
   "@
-   icm\t%0,8,%S1
-   icmy\t%0,8,%S1"
+   icm\t%0,%2,%S1
+   icmy\t%0,%2,%S1"
   [(set_attr "op_type" "RS,RSY")])
 
-(define_insn_and_split "*extractqi"
-  [(set (match_operand:SI 0 "register_operand" "=d")
-        (zero_extract:SI (match_operand:QI 1 "s_operand" "Q")
-                         (match_operand 2 "const_int_operand" "n")
-                         (const_int 0)))
+(define_insn_and_split "*extzv<mode>"
+  [(set (match_operand:GPR 0 "register_operand" "=d")
+       (zero_extract:GPR (match_operand:QI 1 "s_operand" "QS")
+                         (match_operand 2 "const_int_operand" "n")
+                         (const_int 0)))
    (clobber (reg:CC CC_REGNUM))]
-  "!TARGET_64BIT
-   && INTVAL (operands[2]) > 0 && INTVAL (operands[2]) < 8"
+  "INTVAL (operands[2]) > 0
+   && INTVAL (operands[2]) <= GET_MODE_BITSIZE (SImode)"
   "#"
   "&& reload_completed"
   [(parallel
-    [(set (match_dup 0) (unspec:SI [(match_dup 1)] UNSPEC_SETHIGH))
+    [(set (match_dup 0) (unspec:GPR [(match_dup 1) (match_dup 3)] UNSPEC_ICM))
      (clobber (reg:CC CC_REGNUM))])
-    (set (match_dup 0) (lshiftrt:SI (match_dup 0) (match_dup 2)))]
+   (set (match_dup 0) (lshiftrt:GPR (match_dup 0) (match_dup 2)))]
 {
-  operands[2] = GEN_INT (32 - INTVAL (operands[2]));
-  operands[1] = change_address (operands[1], QImode, 0);
+  int bitsize = INTVAL (operands[2]);
+  int size = (bitsize - 1) / BITS_PER_UNIT + 1; /* round up */
+  int mask = ((1ul << size) - 1) << (GET_MODE_SIZE (SImode) - size);
+
+  operands[1] = adjust_address (operands[1], BLKmode, 0);
+  set_mem_size (operands[1], GEN_INT (size));
+  operands[2] = GEN_INT (GET_MODE_BITSIZE (<MODE>mode) - bitsize);
+  operands[3] = GEN_INT (mask);
 })
 
-(define_insn_and_split "*extracthi"
-  [(set (match_operand:SI 0 "register_operand" "=d")
-        (zero_extract:SI (match_operand:QI 1 "s_operand" "Q")
-                         (match_operand 2 "const_int_operand" "n")
-                         (const_int 0)))
+(define_insn_and_split "*extv<mode>"
+  [(set (match_operand:GPR 0 "register_operand" "=d")
+       (sign_extract:GPR (match_operand:QI 1 "s_operand" "QS")
+                         (match_operand 2 "const_int_operand" "n")
+                         (const_int 0)))
    (clobber (reg:CC CC_REGNUM))]
-  "!TARGET_64BIT
-   && INTVAL (operands[2]) >= 8 && INTVAL (operands[2]) < 16"
+  "INTVAL (operands[2]) > 0
+   && INTVAL (operands[2]) <= GET_MODE_BITSIZE (SImode)"
   "#"
   "&& reload_completed"
   [(parallel
-    [(set (match_dup 0) (unspec:SI [(match_dup 1)] UNSPEC_SETHIGH))
+    [(set (match_dup 0) (unspec:GPR [(match_dup 1) (match_dup 3)] UNSPEC_ICM))
      (clobber (reg:CC CC_REGNUM))])
-    (set (match_dup 0) (lshiftrt:SI (match_dup 0) (match_dup 2)))]
+   (parallel
+    [(set (match_dup 0) (ashiftrt:GPR (match_dup 0) (match_dup 2)))
+     (clobber (reg:CC CC_REGNUM))])]
 {
-  operands[2] = GEN_INT (32 - INTVAL (operands[2]));
-  operands[1] = change_address (operands[1], HImode, 0);
+  int bitsize = INTVAL (operands[2]);
+  int size = (bitsize - 1) / BITS_PER_UNIT + 1; /* round up */
+  int mask = ((1ul << size) - 1) << (GET_MODE_SIZE (SImode) - size);
+
+  operands[1] = adjust_address (operands[1], BLKmode, 0);
+  set_mem_size (operands[1], GEN_INT (size));
+  operands[2] = GEN_INT (GET_MODE_BITSIZE (<MODE>mode) - bitsize);
+  operands[3] = GEN_INT (mask);
 })
 
 ;
+; insv instruction patterns
+;
+
+(define_expand "insv"
+  [(set (zero_extract (match_operand 0 "nonimmediate_operand" "")
+                     (match_operand 1 "const_int_operand" "")
+                     (match_operand 2 "const_int_operand" ""))
+       (match_operand 3 "general_operand" ""))]
+  ""
+{
+  if (s390_expand_insv (operands[0], operands[1], operands[2], operands[3]))
+    DONE;
+  FAIL;
+})
+
+(define_insn "*insv<mode>_mem_reg"
+  [(set (zero_extract:P (match_operand:QI 0 "memory_operand" "+Q,S")
+                       (match_operand 1 "const_int_operand" "n,n")
+                       (const_int 0))
+       (match_operand:P 2 "register_operand" "d,d"))]
+  "INTVAL (operands[1]) > 0
+   && INTVAL (operands[1]) <= GET_MODE_BITSIZE (SImode)
+   && INTVAL (operands[1]) % BITS_PER_UNIT == 0"
+{
+    int size = INTVAL (operands[1]) / BITS_PER_UNIT;
+
+    operands[1] = GEN_INT ((1ul << size) - 1);
+    return (which_alternative == 0) ? "stcm\t%2,%1,%S0" 
+                                   : "stcmy\t%2,%1,%S0";
+}
+  [(set_attr "op_type" "RS,RSY")])
+
+(define_insn "*insvdi_mem_reghigh"
+  [(set (zero_extract:DI (match_operand:QI 0 "memory_operand" "+QS")
+                        (match_operand 1 "const_int_operand" "n")
+                        (const_int 0))
+       (lshiftrt:DI (match_operand:DI 2 "register_operand" "d")
+                    (const_int 32)))]
+  "TARGET_64BIT
+   && INTVAL (operands[1]) > 0
+   && INTVAL (operands[1]) <= GET_MODE_BITSIZE (SImode)
+   && INTVAL (operands[1]) % BITS_PER_UNIT == 0"
+{
+    int size = INTVAL (operands[1]) / BITS_PER_UNIT;
+
+    operands[1] = GEN_INT ((1ul << size) - 1);
+    return "stcmh\t%2,%1,%S0";
+}
+[(set_attr "op_type" "RSY")])
+
+(define_insn "*insv<mode>_reg_imm"
+  [(set (zero_extract:P (match_operand:P 0 "register_operand" "+d")
+                       (const_int 16)
+                       (match_operand 1 "const_int_operand" "n"))
+       (match_operand 2 "const_int_operand" "n"))]
+  "TARGET_ZARCH
+   && INTVAL (operands[1]) >= 0
+   && INTVAL (operands[1]) < BITS_PER_WORD
+   && INTVAL (operands[1]) % 16 == 0"
+{
+  switch (BITS_PER_WORD - INTVAL (operands[1]))
+    {
+      case 64: return "iihh\t%0,%x2"; break;
+      case 48: return "iihl\t%0,%x2"; break;
+      case 32: return "iilh\t%0,%x2"; break;
+      case 16: return "iill\t%0,%x2"; break;
+      default: gcc_unreachable();
+    }
+}
+  [(set_attr "op_type" "RI")])
+
+(define_insn "*insv<mode>_reg_extimm"
+  [(set (zero_extract:P (match_operand:P 0 "register_operand" "+d")
+                       (const_int 32)
+                       (match_operand 1 "const_int_operand" "n"))
+       (match_operand 2 "const_int_operand" "n"))]
+  "TARGET_EXTIMM
+   && INTVAL (operands[1]) >= 0
+   && INTVAL (operands[1]) < BITS_PER_WORD
+   && INTVAL (operands[1]) % 32 == 0"
+{
+  switch (BITS_PER_WORD - INTVAL (operands[1]))
+    {
+      case 64: return "iihf\t%0,%o2"; break;
+      case 32: return "iilf\t%0,%o2"; break;
+      default: gcc_unreachable();
+    }
+}
+  [(set_attr "op_type" "RIL")])
+
+;
 ; extendsidi2 instruction pattern(s).
 ;
 
   "#"
   "&& reload_completed"
   [(parallel
-    [(set (match_dup 0) (unspec:DI [(match_dup 1)] UNSPEC_SETHIGH))
+    [(set (match_dup 0) (unspec:DI [(match_dup 1) (const_int 8)] UNSPEC_ICM))
      (clobber (reg:CC CC_REGNUM))])
    (parallel
     [(set (match_dup 0) (ashiftrt:DI (match_dup 0) (const_int 56)))
      (clobber (reg:CC CC_REGNUM))])]
-  "")
+{
+  operands[1] = adjust_address (operands[1], BLKmode, 0);
+  set_mem_size (operands[1], GEN_INT (GET_MODE_SIZE (QImode)));
+})
 
 ;
 ; extend(hi|qi)si2 instruction pattern(s).
   "#"
   "&& reload_completed"
   [(parallel
-    [(set (match_dup 0) (unspec:SI [(match_dup 1)] UNSPEC_SETHIGH))
+    [(set (match_dup 0) (unspec:SI [(match_dup 1) (const_int 8)] UNSPEC_ICM))
      (clobber (reg:CC CC_REGNUM))])
    (parallel
     [(set (match_dup 0) (ashiftrt:SI (match_dup 0) (const_int 24)))
      (clobber (reg:CC CC_REGNUM))])]
-  "")
+{
+  operands[1] = adjust_address (operands[1], BLKmode, 0);
+  set_mem_size (operands[1], GEN_INT (GET_MODE_SIZE (QImode)));
+})
 
 ;
 ; extendqihi2 instruction pattern(s).
      (clobber (reg:CC CC_REGNUM))])]
   "s390_offset_p (operands[0], operands[3], operands[2])
    && s390_offset_p (operands[1], operands[4], operands[2])
+   && !s390_overlap_p (operands[0], operands[1], 
+                       INTVAL (operands[2]) + INTVAL (operands[5]))
    && INTVAL (operands[2]) + INTVAL (operands[5]) <= 256"
   [(parallel
     [(set (match_dup 6) (and:BLK (match_dup 6) (match_dup 7)))
      (clobber (reg:CC CC_REGNUM))])]
   "s390_offset_p (operands[0], operands[3], operands[2])
    && s390_offset_p (operands[1], operands[4], operands[2])
+   && !s390_overlap_p (operands[0], operands[1], 
+                       INTVAL (operands[2]) + INTVAL (operands[5]))
    && INTVAL (operands[2]) + INTVAL (operands[5]) <= 256"
   [(parallel
     [(set (match_dup 6) (ior:BLK (match_dup 6) (match_dup 7)))
      (clobber (reg:CC CC_REGNUM))])]
   "s390_offset_p (operands[0], operands[3], operands[2])
    && s390_offset_p (operands[1], operands[4], operands[2])
+   && !s390_overlap_p (operands[0], operands[1], 
+                       INTVAL (operands[2]) + INTVAL (operands[5]))
    && INTVAL (operands[2]) + INTVAL (operands[5]) <= 256"
   [(parallel
     [(set (match_dup 6) (xor:BLK (match_dup 6) (match_dup 7)))
 (define_insn "rotl<mode>3"
   [(set (match_operand:GPR 0 "register_operand" "=d")
        (rotate:GPR (match_operand:GPR 1 "register_operand" "d")
-                   (match_operand:SI 2 "shift_count_operand" "Y")))]
+                   (match_operand:SI 2 "shift_count_or_setmem_operand" "Y")))]
   "TARGET_CPU_ZARCH"
   "rll<g>\t%0,%1,%Y2"
   [(set_attr "op_type"  "RSE")
    (set_attr "atype"    "reg")])
 
+(define_insn "*rotl<mode>3_and"
+  [(set (match_operand:GPR 0 "register_operand" "=d")
+       (rotate:GPR (match_operand:GPR 1 "register_operand" "d")
+                   (and:SI (match_operand:SI 2 "shift_count_or_setmem_operand" "Y")
+                           (match_operand:SI 3 "const_int_operand"   "n"))))]
+  "TARGET_CPU_ZARCH && (INTVAL (operands[3]) & 63) == 63"
+  "rll<g>\t%0,%1,%Y2"
+  [(set_attr "op_type"  "RSE")
+   (set_attr "atype"    "reg")])
+
 
 ;;
 ;;- Shift instructions.
 (define_expand "<shift>di3"
   [(set (match_operand:DI 0 "register_operand" "")
         (SHIFT:DI (match_operand:DI 1 "register_operand" "")
-                  (match_operand:SI 2 "shift_count_operand" "")))]
+                  (match_operand:SI 2 "shift_count_or_setmem_operand" "")))]
   ""
   "")
 
 (define_insn "*<shift>di3_31"
   [(set (match_operand:DI 0 "register_operand" "=d")
         (SHIFT:DI (match_operand:DI 1 "register_operand" "0")
-                  (match_operand:SI 2 "shift_count_operand" "Y")))]
+                  (match_operand:SI 2 "shift_count_or_setmem_operand" "Y")))]
   "!TARGET_64BIT"
   "s<lr>dl\t%0,%Y2"
   [(set_attr "op_type"  "RS")
 (define_insn "*<shift>di3_64"
   [(set (match_operand:DI 0 "register_operand" "=d")
         (SHIFT:DI (match_operand:DI 1 "register_operand" "d")
-                  (match_operand:SI 2 "shift_count_operand" "Y")))]
+                  (match_operand:SI 2 "shift_count_or_setmem_operand" "Y")))]
   "TARGET_64BIT"
   "s<lr>lg\t%0,%1,%Y2"
   [(set_attr "op_type"  "RSE")
    (set_attr "atype"    "reg")])
 
+(define_insn "*<shift>di3_31_and"
+  [(set (match_operand:DI 0 "register_operand" "=d")
+        (SHIFT:DI (match_operand:DI 1 "register_operand" "0")
+                  (and:SI (match_operand:SI 2 "shift_count_or_setmem_operand" "Y")
+                         (match_operand:SI 3 "const_int_operand"   "n"))))]
+  "!TARGET_64BIT && (INTVAL (operands[3]) & 63) == 63"
+  "s<lr>dl\t%0,%Y2"
+  [(set_attr "op_type"  "RS")
+   (set_attr "atype"    "reg")])
+
+(define_insn "*<shift>di3_64_and"
+  [(set (match_operand:DI 0 "register_operand" "=d")
+        (SHIFT:DI (match_operand:DI 1 "register_operand" "d")
+                  (and:SI (match_operand:SI 2 "shift_count_or_setmem_operand" "Y")
+                         (match_operand:SI 3 "const_int_operand"   "n"))))]
+  "TARGET_64BIT && (INTVAL (operands[3]) & 63) == 63"
+  "s<lr>lg\t%0,%1,%Y2"
+  [(set_attr "op_type"  "RSE")
+   (set_attr "atype"    "reg")])
+
 ;
 ; ashrdi3 instruction pattern(s).
 ;
   [(parallel
     [(set (match_operand:DI 0 "register_operand" "")
           (ashiftrt:DI (match_operand:DI 1 "register_operand" "")
-                       (match_operand:SI 2 "shift_count_operand" "")))
+                       (match_operand:SI 2 "shift_count_or_setmem_operand" "")))
      (clobber (reg:CC CC_REGNUM))])]
   ""
   "")
 (define_insn "*ashrdi3_cc_31"
   [(set (reg CC_REGNUM)
         (compare (ashiftrt:DI (match_operand:DI 1 "register_operand" "0")
-                              (match_operand:SI 2 "shift_count_operand" "Y"))
+                              (match_operand:SI 2 "shift_count_or_setmem_operand" "Y"))
                  (const_int 0)))
    (set (match_operand:DI 0 "register_operand" "=d")
         (ashiftrt:DI (match_dup 1) (match_dup 2)))]
 (define_insn "*ashrdi3_cconly_31"
   [(set (reg CC_REGNUM)
         (compare (ashiftrt:DI (match_operand:DI 1 "register_operand" "0")
-                              (match_operand:SI 2 "shift_count_operand" "Y"))
+                              (match_operand:SI 2 "shift_count_or_setmem_operand" "Y"))
                  (const_int 0)))
    (clobber (match_scratch:DI 0 "=d"))]
   "!TARGET_64BIT && s390_match_ccmode(insn, CCSmode)"
 (define_insn "*ashrdi3_31"
   [(set (match_operand:DI 0 "register_operand" "=d")
         (ashiftrt:DI (match_operand:DI 1 "register_operand" "0")
-                     (match_operand:SI 2 "shift_count_operand" "Y")))
+                     (match_operand:SI 2 "shift_count_or_setmem_operand" "Y")))
    (clobber (reg:CC CC_REGNUM))]
   "!TARGET_64BIT"
   "srda\t%0,%Y2"
 (define_insn "*ashrdi3_cc_64"
   [(set (reg CC_REGNUM)
         (compare (ashiftrt:DI (match_operand:DI 1 "register_operand" "d")
-                              (match_operand:SI 2 "shift_count_operand" "Y"))
+                              (match_operand:SI 2 "shift_count_or_setmem_operand" "Y"))
                  (const_int 0)))
    (set (match_operand:DI 0 "register_operand" "=d")
         (ashiftrt:DI (match_dup 1) (match_dup 2)))]
 (define_insn "*ashrdi3_cconly_64"
   [(set (reg CC_REGNUM)
         (compare (ashiftrt:DI (match_operand:DI 1 "register_operand" "d")
-                              (match_operand:SI 2 "shift_count_operand" "Y"))
+                              (match_operand:SI 2 "shift_count_or_setmem_operand" "Y"))
                  (const_int 0)))
    (clobber (match_scratch:DI 0 "=d"))]
   "s390_match_ccmode(insn, CCSmode) && TARGET_64BIT"
 (define_insn "*ashrdi3_64"
   [(set (match_operand:DI 0 "register_operand" "=d")
         (ashiftrt:DI (match_operand:DI 1 "register_operand" "d")
-                     (match_operand:SI 2 "shift_count_operand" "Y")))
+                     (match_operand:SI 2 "shift_count_or_setmem_operand" "Y")))
    (clobber (reg:CC CC_REGNUM))]
   "TARGET_64BIT"
   "srag\t%0,%1,%Y2"
    (set_attr "atype"    "reg")])
 
 
+; shift pattern with implicit ANDs
+
+(define_insn "*ashrdi3_cc_31_and"
+  [(set (reg CC_REGNUM)
+        (compare (ashiftrt:DI (match_operand:DI 1 "register_operand" "0")
+                              (and:SI (match_operand:SI 2 "shift_count_or_setmem_operand" "Y")
+                                     (match_operand:SI 3 "const_int_operand"   "n")))
+                (const_int 0)))
+   (set (match_operand:DI 0 "register_operand" "=d")
+        (ashiftrt:DI (match_dup 1) (and:SI (match_dup 2) (match_dup 3))))]
+  "!TARGET_64BIT && s390_match_ccmode(insn, CCSmode)
+   && (INTVAL (operands[3]) & 63) == 63"
+  "srda\t%0,%Y2"
+  [(set_attr "op_type"  "RS")
+   (set_attr "atype"    "reg")])
+
+(define_insn "*ashrdi3_cconly_31_and"
+  [(set (reg CC_REGNUM)
+        (compare (ashiftrt:DI (match_operand:DI 1 "register_operand" "0")
+                              (and:SI (match_operand:SI 2 "shift_count_or_setmem_operand" "Y")
+                                     (match_operand:SI 3 "const_int_operand"   "n")))
+                 (const_int 0)))
+   (clobber (match_scratch:DI 0 "=d"))]
+  "!TARGET_64BIT && s390_match_ccmode(insn, CCSmode)
+   && (INTVAL (operands[3]) & 63) == 63"
+  "srda\t%0,%Y2"
+  [(set_attr "op_type"  "RS")
+   (set_attr "atype"    "reg")])
+
+(define_insn "*ashrdi3_31_and"
+  [(set (match_operand:DI 0 "register_operand" "=d")
+        (ashiftrt:DI (match_operand:DI 1 "register_operand" "0")
+                     (and:SI (match_operand:SI 2 "shift_count_or_setmem_operand" "Y")
+                            (match_operand:SI 3 "const_int_operand"   "n"))))
+   (clobber (reg:CC CC_REGNUM))]
+  "!TARGET_64BIT && (INTVAL (operands[3]) & 63) == 63"
+  "srda\t%0,%Y2"
+  [(set_attr "op_type"  "RS")
+   (set_attr "atype"    "reg")])
+
+(define_insn "*ashrdi3_cc_64_and"
+  [(set (reg CC_REGNUM)
+        (compare (ashiftrt:DI (match_operand:DI 1 "register_operand" "d")
+                              (and:SI (match_operand:SI 2 "shift_count_or_setmem_operand" "Y")
+                                     (match_operand:SI 3 "const_int_operand"   "n")))
+                (const_int 0)))
+   (set (match_operand:DI 0 "register_operand" "=d")
+        (ashiftrt:DI (match_dup 1) (and:SI (match_dup 2) (match_dup 3))))]
+  "TARGET_64BIT && s390_match_ccmode(insn, CCSmode)
+   && (INTVAL (operands[3]) & 63) == 63"
+  "srag\t%0,%1,%Y2"
+  [(set_attr "op_type"  "RSE")
+   (set_attr "atype"    "reg")])
+
+(define_insn "*ashrdi3_cconly_64_and"
+  [(set (reg CC_REGNUM)
+        (compare (ashiftrt:DI (match_operand:DI 1 "register_operand" "d")
+                              (and:SI (match_operand:SI 2 "shift_count_or_setmem_operand" "Y")
+                                     (match_operand:SI 3 "const_int_operand"   "n")))
+                 (const_int 0)))
+   (clobber (match_scratch:DI 0 "=d"))]
+  "TARGET_64BIT && s390_match_ccmode(insn, CCSmode)
+   && (INTVAL (operands[3]) & 63) == 63"
+  "srag\t%0,%1,%Y2"
+  [(set_attr "op_type"  "RSE")
+   (set_attr "atype"    "reg")])
+
+(define_insn "*ashrdi3_64_and"
+  [(set (match_operand:DI 0 "register_operand" "=d")
+        (ashiftrt:DI (match_operand:DI 1 "register_operand" "d")
+                     (and:SI (match_operand:SI 2 "shift_count_or_setmem_operand" "Y")
+                            (match_operand:SI 3 "const_int_operand"   "n"))))
+   (clobber (reg:CC CC_REGNUM))]
+  "TARGET_64BIT && (INTVAL (operands[3]) & 63) == 63"
+  "srag\t%0,%1,%Y2"
+  [(set_attr "op_type"  "RSE")
+   (set_attr "atype"    "reg")])
+
 ;
 ; (ashl|lshr)si3 instruction pattern(s).
 ;
 (define_insn "<shift>si3"
   [(set (match_operand:SI 0 "register_operand" "=d")
         (SHIFT:SI (match_operand:SI 1 "register_operand" "0")
-                  (match_operand:SI 2 "shift_count_operand" "Y")))]
+                  (match_operand:SI 2 "shift_count_or_setmem_operand" "Y")))]
   ""
   "s<lr>l\t%0,%Y2"
   [(set_attr "op_type"  "RS")
    (set_attr "atype"    "reg")])
 
+(define_insn "*<shift>si3_and"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+        (SHIFT:SI (match_operand:SI 1 "register_operand" "0")
+                  (and:SI (match_operand:SI 2 "shift_count_or_setmem_operand" "Y")
+                         (match_operand:SI 3 "const_int_operand"   "n"))))]
+  "(INTVAL (operands[3]) & 63) == 63"
+  "s<lr>l\t%0,%Y2"
+  [(set_attr "op_type"  "RS")
+   (set_attr "atype"    "reg")])
+
 ;
 ; ashrsi3 instruction pattern(s).
 ;
 (define_insn "*ashrsi3_cc"
   [(set (reg CC_REGNUM)
         (compare (ashiftrt:SI (match_operand:SI 1 "register_operand" "0")
-                              (match_operand:SI 2 "shift_count_operand" "Y"))
+                              (match_operand:SI 2 "shift_count_or_setmem_operand" "Y"))
                  (const_int 0)))
    (set (match_operand:SI 0 "register_operand" "=d")
         (ashiftrt:SI (match_dup 1) (match_dup 2)))]
 (define_insn "*ashrsi3_cconly"
   [(set (reg CC_REGNUM)
         (compare (ashiftrt:SI (match_operand:SI 1 "register_operand" "0")
-                              (match_operand:SI 2 "shift_count_operand" "Y"))
+                              (match_operand:SI 2 "shift_count_or_setmem_operand" "Y"))
                  (const_int 0)))
    (clobber (match_scratch:SI 0 "=d"))]
   "s390_match_ccmode(insn, CCSmode)"
 (define_insn "ashrsi3"
   [(set (match_operand:SI 0 "register_operand" "=d")
         (ashiftrt:SI (match_operand:SI 1 "register_operand" "0")
-                     (match_operand:SI 2 "shift_count_operand" "Y")))
+                     (match_operand:SI 2 "shift_count_or_setmem_operand" "Y")))
    (clobber (reg:CC CC_REGNUM))]
   ""
   "sra\t%0,%Y2"
   [(set_attr "op_type"  "RS")
    (set_attr "atype"    "reg")])
 
+; with implicit ANDs
+
+(define_insn "*ashrsi3_cc_and"
+  [(set (reg CC_REGNUM)
+        (compare (ashiftrt:SI (match_operand:SI 1 "register_operand" "0")
+                              (and:SI (match_operand:SI 2 "shift_count_or_setmem_operand" "Y")
+                                     (match_operand:SI 3 "const_int_operand"   "n")))
+                 (const_int 0)))
+   (set (match_operand:SI 0 "register_operand" "=d")
+        (ashiftrt:SI (match_dup 1) (and:SI (match_dup 2) (match_dup 3))))]
+  "s390_match_ccmode(insn, CCSmode) && (INTVAL (operands[3]) & 63) == 63"
+  "sra\t%0,%Y2"
+  [(set_attr "op_type"  "RS")
+   (set_attr "atype"    "reg")])
+
+
+(define_insn "*ashrsi3_cconly_and"
+  [(set (reg CC_REGNUM)
+        (compare (ashiftrt:SI (match_operand:SI 1 "register_operand" "0")
+                              (and:SI (match_operand:SI 2 "shift_count_or_setmem_operand" "Y")
+                                     (match_operand:SI 3 "const_int_operand"   "n")))
+                 (const_int 0)))
+   (clobber (match_scratch:SI 0 "=d"))]
+  "s390_match_ccmode(insn, CCSmode) && (INTVAL (operands[3]) & 63) == 63"
+  "sra\t%0,%Y2"
+  [(set_attr "op_type"  "RS")
+   (set_attr "atype"    "reg")])
+
+(define_insn "*ashrsi3_and"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+        (ashiftrt:SI (match_operand:SI 1 "register_operand" "0")
+                     (and:SI (match_operand:SI 2 "shift_count_or_setmem_operand" "Y")
+                            (match_operand:SI 3 "const_int_operand"   "n"))))
+   (clobber (reg:CC CC_REGNUM))]
+  "(INTVAL (operands[3]) & 63) == 63"
+  "sra\t%0,%Y2"
+  [(set_attr "op_type"  "RS")
+   (set_attr "atype"    "reg")])
+
 
 ;;
 ;; Branch instruction patterns.
 ; compare and swap patterns.
 ;
 
-(define_insn "sync_compare_and_swap<mode>"
-  [(set (match_operand:GPR 0 "register_operand" "=r")
-        (match_operand:GPR 1 "memory_operand" "+Q"))
-   (set (match_dup 1)
-       (unspec_volatile:GPR
-         [(match_dup 1)
-          (match_operand:GPR 2 "register_operand" "0")
-          (match_operand:GPR 3 "register_operand" "r")]
-         UNSPECV_CAS))
-   (clobber (reg:CC CC_REGNUM))]
+(define_expand "sync_compare_and_swap<mode>"
+  [(parallel
+    [(set (match_operand:TDSI 0 "register_operand" "")
+         (match_operand:TDSI 1 "memory_operand" ""))
+     (set (match_dup 1)
+         (unspec_volatile:TDSI
+           [(match_dup 1)
+            (match_operand:TDSI 2 "register_operand" "")
+            (match_operand:TDSI 3 "register_operand" "")]
+           UNSPECV_CAS))
+     (set (reg:CCZ1 CC_REGNUM)
+         (compare:CCZ1 (match_dup 1) (match_dup 2)))])]
+  "")
+
+(define_expand "sync_compare_and_swap<mode>"
+  [(parallel
+    [(set (match_operand:HQI 0 "register_operand" "")
+         (match_operand:HQI 1 "memory_operand" ""))
+     (set (match_dup 1)
+         (unspec_volatile:HQI
+           [(match_dup 1)
+            (match_operand:HQI 2 "general_operand" "")
+            (match_operand:HQI 3 "general_operand" "")]
+           UNSPECV_CAS))
+     (set (reg:CCZ1 CC_REGNUM)
+         (compare:CCZ1 (match_dup 1) (match_dup 2)))])]
   ""
-  "cs<g>\t%0,%3,%S1"
-  [(set_attr "op_type" "RS<E>")
-   (set_attr "type"   "sem")])
+  "s390_expand_cs_hqi (<MODE>mode, operands[0], operands[1], 
+                      operands[2], operands[3]); DONE;")
 
 (define_expand "sync_compare_and_swap_cc<mode>"
   [(parallel
-    [(set (match_operand:GPR 0 "register_operand" "")
-          (match_operand:GPR 1 "memory_operand" ""))
+    [(set (match_operand:TDSI 0 "register_operand" "")
+         (match_operand:TDSI 1 "memory_operand" ""))
      (set (match_dup 1)
-         (unspec_volatile:GPR
+         (unspec_volatile:TDSI
            [(match_dup 1)
-            (match_operand:GPR 2 "register_operand" "")
-            (match_operand:GPR 3 "register_operand" "")]
+            (match_operand:TDSI 2 "register_operand" "")
+            (match_operand:TDSI 3 "register_operand" "")]
            UNSPECV_CAS))
      (set (match_dup 4)
          (compare:CCZ1 (match_dup 1) (match_dup 2)))])]
   ""
 {
+  /* Emulate compare.  */
   operands[4] = gen_rtx_REG (CCZ1mode, CC_REGNUM);
   s390_compare_op0 = operands[1];
   s390_compare_op1 = operands[2];
   s390_compare_emitted = operands[4];
 })
 
-(define_insn "*sync_compare_and_swap_cc<mode>"
+(define_insn "*sync_compare_and_swap<mode>"
+  [(set (match_operand:DP 0 "register_operand" "=r")
+       (match_operand:DP 1 "memory_operand" "+Q"))
+   (set (match_dup 1)
+       (unspec_volatile:DP
+         [(match_dup 1)
+          (match_operand:DP 2 "register_operand" "0")
+          (match_operand:DP 3 "register_operand" "r")]
+         UNSPECV_CAS))
+   (set (reg:CCZ1 CC_REGNUM)
+       (compare:CCZ1 (match_dup 1) (match_dup 2)))]
+  ""
+  "cds<tg>\t%0,%3,%S1"
+  [(set_attr "op_type" "RS<TE>")
+   (set_attr "type"   "sem")])
+
+(define_insn "*sync_compare_and_swap<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=r")
        (match_operand:GPR 1 "memory_operand" "+Q"))
    (set (match_dup 1)
    (set_attr "type"   "sem")])
 
 
+;
+; Other atomic instruction patterns.
+;
+
+(define_expand "sync_lock_test_and_set<mode>"
+  [(match_operand:HQI 0 "register_operand")
+   (match_operand:HQI 1 "memory_operand")
+   (match_operand:HQI 2 "general_operand")]
+  ""
+  "s390_expand_atomic (<MODE>mode, SET, operands[0], operands[1], 
+                      operands[2], false); DONE;")
+
+(define_expand "sync_<atomic><mode>"
+  [(set (match_operand:HQI 0 "memory_operand")
+       (ATOMIC:HQI (match_dup 0)
+                   (match_operand:HQI 1 "general_operand")))]
+  ""
+  "s390_expand_atomic (<MODE>mode, <CODE>, NULL_RTX, operands[0], 
+                      operands[1], false); DONE;")
+
+(define_expand "sync_old_<atomic><mode>"
+  [(set (match_operand:HQI 0 "register_operand")
+       (match_operand:HQI 1 "memory_operand"))
+   (set (match_dup 1)
+       (ATOMIC:HQI (match_dup 1)
+                   (match_operand:HQI 2 "general_operand")))]
+  ""
+  "s390_expand_atomic (<MODE>mode, <CODE>, operands[0], operands[1], 
+                      operands[2], false); DONE;")
+
+(define_expand "sync_new_<atomic><mode>"
+  [(set (match_operand:HQI 0 "register_operand")
+       (ATOMIC:HQI (match_operand:HQI 1 "memory_operand")
+                   (match_operand:HQI 2 "general_operand"))) 
+   (set (match_dup 1) (ATOMIC:HQI (match_dup 1) (match_dup 2)))]
+  ""
+  "s390_expand_atomic (<MODE>mode, <CODE>, operands[0], operands[1], 
+                      operands[2], true); DONE;")
+
 ;;
 ;;- Miscellaneous instructions.
 ;;