s390.h (EXTRA_CC_MODES): Add CCLmode.
authorUlrich Weigand <uweigand@de.ibm.com>
Sat, 29 Sep 2001 22:56:14 +0000 (22:56 +0000)
committerUlrich Weigand <uweigand@gcc.gnu.org>
Sat, 29 Sep 2001 22:56:14 +0000 (22:56 +0000)
* config/s390/s390.h (EXTRA_CC_MODES): Add CCLmode.
(SELECT_CC_MODE): Use s390_select_ccmode.
* config/s390/s390-protos.h (s390_select_ccmode): Add.
* config/s390/s390.c (s390_select_ccmode): New.
(s390_match_ccmode): Add CCLmode.
(s390_branch_condition_mask, s390_branch_condition_mnemonic): New.
(output_branch_condition, output_inverse_branch_condition): Removed.
(print_operand): Use s390_branch_condition_mnemonic.
* config/s390/s390.md (addsi3_cc, addsi3_cconly, addsi3_cconly2,
subsi3_cc, subsi3_cconly): Use logical instructions and CCLmode.
(bunordered, bordered, buneq, bungt, bunlt, bnuge, bunle, bltgt): New.

* config/s390/s390.c (check_and_change_labels): Preserve CC mode
when converting conditional branches to far branches.
* config/s390/s390.md (cmpstr_const, cmpstr_64, cmpstr_31, cmpint_si,
cmpint_di): Use CCSmode instead of CCUmode.

* config/s390/s390.c (legitimate_la_operand_p): New.
* config/s390/s390-protos.h (legitimate_la_operand_p): Add.
* config/s390/s390.md (movsi): Convert load address patterns to
arithmetic operations when necessary.
(addaddr_picR, addaddr_picL, addaddr_picN): Removed.
(do_la): Renamed to *do_la and use legitimate_la_operand_p.
(*do_la_reg_0): Don't use before reload.

* config/s390/s390.c (legitimize_address): Make more efficient
use of two-register addressing mode.

* config/s390/s390.c (s390_function_prologue): Fix incorrect prolog
with -mno-backchain in some corner cases.

* config/s390/s390.md (cmpsi_cct): Operands 0 and 1 do not commute.

From-SVN: r45891

gcc/ChangeLog
gcc/config/s390/s390-protos.h
gcc/config/s390/s390.c
gcc/config/s390/s390.h
gcc/config/s390/s390.md

index 8e5d1827c60d248b6d10580cd0eaebb006a059bf..c89d7c81ec3ae4ec7d4b21ff89fda5556f72585e 100644 (file)
@@ -1,3 +1,38 @@
+2001-09-30  Ulrich Weigand  <uweigand@de.ibm.com>
+
+       * config/s390/s390.h (EXTRA_CC_MODES): Add CCLmode.
+       (SELECT_CC_MODE): Use s390_select_ccmode.
+       * config/s390/s390-protos.h (s390_select_ccmode): Add.
+       * config/s390/s390.c (s390_select_ccmode): New.
+       (s390_match_ccmode): Add CCLmode.
+       (s390_branch_condition_mask, s390_branch_condition_mnemonic): New.
+       (output_branch_condition, output_inverse_branch_condition): Removed.
+       (print_operand): Use s390_branch_condition_mnemonic.
+       * config/s390/s390.md (addsi3_cc, addsi3_cconly, addsi3_cconly2,
+       subsi3_cc, subsi3_cconly): Use logical instructions and CCLmode.
+       (bunordered, bordered, buneq, bungt, bunlt, bnuge, bunle, bltgt): New.
+
+       * config/s390/s390.c (check_and_change_labels): Preserve CC mode
+       when converting conditional branches to far branches.
+       * config/s390/s390.md (cmpstr_const, cmpstr_64, cmpstr_31, cmpint_si,
+       cmpint_di): Use CCSmode instead of CCUmode.
+
+       * config/s390/s390.c (legitimate_la_operand_p): New.
+       * config/s390/s390-protos.h (legitimate_la_operand_p): Add.
+       * config/s390/s390.md (movsi): Convert load address patterns to
+       arithmetic operations when necessary.
+       (addaddr_picR, addaddr_picL, addaddr_picN): Removed.
+       (do_la): Renamed to *do_la and use legitimate_la_operand_p.
+       (*do_la_reg_0): Don't use before reload.
+
+       * config/s390/s390.c (legitimize_address): Make more efficient
+       use of two-register addressing mode.
+
+       * config/s390/s390.c (s390_function_prologue): Fix incorrect prolog
+       with -mno-backchain in some corner cases.
+
+       * config/s390/s390.md (cmpsi_cct): Operands 0 and 1 do not commute.
+
 2001-09-29  Alexandre Oliva  <aoliva@redhat.com>
 
        * reload.c (find_reloads): Mark new USE insns with QImode.
index 7f168437ea4bcd2c9acd7dd6cc4ca3bc33643b06..baee5a09ea05fcbda98e4979869a1974aaea4f5b 100644 (file)
@@ -42,7 +42,9 @@ extern int load_multiple_operation PARAMS ((rtx, enum machine_mode));
 extern int store_multiple_operation PARAMS ((rtx, enum machine_mode));
 
 extern int s390_match_ccmode PARAMS ((rtx, enum machine_mode));
+extern enum machine_mode s390_select_ccmode PARAMS ((enum rtx_code, rtx, rtx));
 extern int symbolic_reference_mentioned_p PARAMS ((rtx));
+extern int legitimate_la_operand_p PARAMS ((rtx));
 extern int legitimate_pic_operand_p PARAMS ((rtx));
 extern int legitimate_constant_p PARAMS ((rtx));
 extern int legitimate_address_p PARAMS ((enum machine_mode, rtx, int));
index e4bc735209e4f210fca10a85df4dcf3d3e09e4d8..647a5fd5380f7bc993b9930c49e14c0fe35f4902 100644 (file)
@@ -94,11 +94,11 @@ struct s390_address
 };
 
 static int s390_match_ccmode_set PARAMS ((rtx, enum machine_mode));
+static int s390_branch_condition_mask PARAMS ((rtx));
+static const char *s390_branch_condition_mnemonic PARAMS ((rtx, int));
 static int base_n_index_p PARAMS ((rtx));
 static int check_mode PARAMS ((rtx, enum machine_mode *));
 static int s390_decompose_address PARAMS ((rtx, struct s390_address *, int));
-static void output_branch_condition PARAMS ((FILE *, rtx));
-static void output_inverse_branch_condition PARAMS ((FILE *, rtx));
 static int reg_used_in_mem_p PARAMS ((int, rtx));
 static int addr_generation_dependency_p PARAMS ((rtx, rtx));
 static int other_chunk PARAMS ((int *, int, int));
@@ -135,9 +135,6 @@ s390_match_ccmode_set (set, req_mode)
   set_mode = GET_MODE (SET_DEST (set));
   switch (set_mode)
     {
-    case CCmode:
-      return 0;
-
     case CCSmode:
       if (req_mode != CCSmode)
         return 0;
@@ -146,6 +143,10 @@ s390_match_ccmode_set (set, req_mode)
       if (req_mode != CCUmode)
         return 0;
       break;
+    case CCLmode:
+      if (req_mode != CCLmode)
+        return 0;
+      break;
     case CCZmode:
       if (req_mode != CCSmode && req_mode != CCUmode && req_mode != CCTmode)
         return 0;
@@ -184,6 +185,161 @@ s390_match_ccmode (insn, req_mode)
   return 1;
 }
 
+/* Given a comparison code OP (EQ, NE, etc.) and the operands 
+   OP0 and OP1 of a COMPARE, return the mode to be used for the 
+   comparison.  */
+
+enum machine_mode
+s390_select_ccmode (code, op0, op1) 
+     enum rtx_code code;
+     rtx op0;
+     rtx op1;
+{
+  switch (code)
+    {
+      case EQ:
+      case NE:
+       if (GET_CODE (op0) == PLUS || GET_CODE (op0) == MINUS
+           || GET_CODE (op1) == NEG)
+         return CCLmode;
+
+       return CCZmode;
+
+      case LE:
+      case LT:
+      case GE:
+      case GT:
+      case UNORDERED:
+      case ORDERED:
+      case UNEQ:
+      case UNLE:
+      case UNLT:
+      case UNGE:
+      case UNGT:
+      case LTGT:
+       return CCSmode;
+
+      case LEU:
+      case LTU:
+      case GEU:
+      case GTU:
+       return CCUmode;
+
+      default:
+       abort ();
+    }
+}
+
+/* Return branch condition mask to implement a branch 
+   specified by CODE.  */
+
+static int
+s390_branch_condition_mask (code)
+    rtx code;
+{ 
+  const int CC0 = 1 << 3;
+  const int CC1 = 1 << 2;
+  const int CC2 = 1 << 1;
+  const int CC3 = 1 << 0;
+
+  if (GET_CODE (XEXP (code, 0)) != REG
+      || REGNO (XEXP (code, 0)) != CC_REGNUM
+      || XEXP (code, 1) != const0_rtx)
+    abort ();
+
+  switch (GET_MODE (XEXP (code, 0)))
+    {
+    case CCZmode:
+      switch (GET_CODE (code))
+        {
+        case EQ:       return CC0;
+       case NE:        return CC1 | CC2 | CC3;
+       default:
+         abort ();
+        }
+      break;
+
+    case CCLmode:
+      switch (GET_CODE (code))
+        {
+        case EQ:       return CC0 | CC2;
+       case NE:        return CC1 | CC3;
+       case UNORDERED: return CC2 | CC3;  /* carry */
+       case ORDERED:   return CC0 | CC1;  /* no carry */
+       default:
+         abort ();
+        }
+      break;
+
+    case CCUmode:
+      switch (GET_CODE (code))
+        {
+        case EQ:       return CC0;
+        case NE:       return CC1 | CC2 | CC3;
+        case LTU:      return CC1;
+        case GTU:      return CC2;
+        case LEU:      return CC0 | CC1;
+        case GEU:      return CC0 | CC2;
+       default:
+         abort ();
+        }
+      break;
+
+    case CCSmode:
+      switch (GET_CODE (code))
+        {
+        case EQ:       return CC0;
+        case NE:       return CC1 | CC2 | CC3;
+        case LT:       return CC1;
+        case GT:       return CC2;
+        case LE:       return CC0 | CC1;
+        case GE:       return CC0 | CC2;
+       case UNORDERED: return CC3;
+       case ORDERED:   return CC0 | CC1 | CC2;
+       case UNEQ:      return CC0 | CC3;
+        case UNLT:     return CC1 | CC3;
+        case UNGT:     return CC2 | CC3;
+        case UNLE:     return CC0 | CC1 | CC3;
+        case UNGE:     return CC0 | CC2 | CC3;
+       case LTGT:      return CC1 | CC2;
+       default:
+         abort ();
+        }
+
+    default:
+      abort ();
+    }
+}
+
+/* If INV is false, return assembler mnemonic string to implement 
+   a branch specified by CODE.  If INV is true, return mnemonic 
+   for the corresponding inverted branch.  */
+
+static const char *
+s390_branch_condition_mnemonic (code, inv)
+     rtx code;
+     int inv;
+{
+  static const char *mnemonic[16] =
+    {
+      NULL, "o", "h", "nle",
+      "l", "nhe", "lh", "ne",
+      "e", "nlh", "he", "nl",
+      "le", "nh", "no", NULL
+    };
+
+  int mask = s390_branch_condition_mask (code);
+
+  if (inv)
+    mask ^= 15;
+
+  if (mask < 1 || mask > 14)
+    abort ();
+
+  return mnemonic[mask];
+}
+
+
 /* Change optimizations to be performed, depending on the 
    optimization level.
 
@@ -887,6 +1043,40 @@ legitimate_address_p (mode, addr, strict)
   return s390_decompose_address (addr, NULL, strict);
 }
 
+/* Return 1 if OP is a valid operand for the LA instruction.
+   In 31-bit, we need to prove that the result is used as an
+   address, as LA performs only a 31-bit addition.  */
+
+int
+legitimate_la_operand_p (op)
+     register rtx op;
+{
+  struct s390_address addr;
+  if (!s390_decompose_address (op, &addr, FALSE))
+    return FALSE;
+
+  if (TARGET_64BIT)
+    return TRUE;
+
+  /* Use of the base or stack pointer implies address.  */
+
+  if (addr.base && GET_CODE (addr.base) == REG)
+    {
+      if (REGNO (addr.base) == BASE_REGISTER
+          || REGNO (addr.base) == STACK_POINTER_REGNUM)
+        return TRUE;
+    }
+
+  if (addr.indx && GET_CODE (addr.indx) == REG)
+    {
+      if (REGNO (addr.indx) == BASE_REGISTER
+          || REGNO (addr.indx) == STACK_POINTER_REGNUM)
+        return TRUE;
+    }
+
+  return FALSE;
+}
+
 /* Return a legitimate reference for ORIG (an address) using the
    register REG.  If REG is 0, a new pseudo is generated.
 
@@ -1199,87 +1389,52 @@ legitimize_address (x, oldx, mode)
      register rtx oldx ATTRIBUTE_UNUSED;
      enum machine_mode mode ATTRIBUTE_UNUSED;
 {
-  if (flag_pic && SYMBOLIC_CONST (x))
-    return legitimize_pic_address (x, 0);
-
-  return x;
-}
+  rtx constant_term = const0_rtx;
 
-
-/* Output branch condition code of CODE in assembler
-   syntax to stdio stream FILE.  */
-
-static void
-output_branch_condition (file, code)
-     FILE *file;
-     rtx code;
-{
-  switch (GET_CODE (code)) 
+  if (flag_pic)
     {
-    case EQ:
-      fprintf (file, "e");
-      break;
-    case NE:
-      fprintf (file, "ne");
-      break;
-    case GT:
-    case GTU:
-      fprintf (file, "h");
-      break;
-    case LT:
-    case LTU:
-      fprintf (file, "l");
-      break;
-    case GE:
-    case GEU:
-      fprintf (file, "he");
-      break;
-    case LE:
-    case LEU:
-      fprintf (file, "le");
-      break;
-    default:
-      fatal_insn ("Unknown CC code", code);
+      if (SYMBOLIC_CONST (x)
+          || (GET_CODE (x) == PLUS 
+              && (SYMBOLIC_CONST (XEXP (x, 0)) 
+                  || SYMBOLIC_CONST (XEXP (x, 1)))))
+         x = legitimize_pic_address (x, 0);
+
+      if (legitimate_address_p (mode, x, FALSE))
+       return x;
     }
-}
 
-/* Output the inverse of the branch condition code of CODE 
-   in assembler syntax to stdio stream FILE.  */
+  x = eliminate_constant_term (x, &constant_term);
 
-static void
-output_inverse_branch_condition (file, code)
-     FILE *file;
-     rtx code;
-{
-  switch (GET_CODE (code)) 
+  if (GET_CODE (x) == PLUS)
     {
-    case EQ:
-      fprintf (file, "ne");
-      break;
-    case NE:
-      fprintf (file, "e");
-      break;
-    case GT:
-    case GTU:
-      fprintf (file, "nh");
-      break;
-    case LT:
-    case LTU:
-      fprintf (file, "nl");
-      break;
-    case GE:
-    case GEU:
-      fprintf (file, "nhe");
-      break;
-    case LE:
-    case LEU:
-      fprintf (file, "nle");
-      break;
-    default:
-      fatal_insn ("Unknown CC code", code);
+      if (GET_CODE (XEXP (x, 0)) == REG)
+       {
+         register rtx temp = gen_reg_rtx (Pmode);
+         register rtx val  = force_operand (XEXP (x, 1), temp);
+         if (val != temp)
+           emit_move_insn (temp, val);
+
+         x = gen_rtx_PLUS (Pmode, XEXP (x, 0), temp);
+       }
+
+      else if (GET_CODE (XEXP (x, 1)) == REG)
+       {
+         register rtx temp = gen_reg_rtx (Pmode);
+         register rtx val  = force_operand (XEXP (x, 0), temp);
+         if (val != temp)
+           emit_move_insn (temp, val);
+
+         x = gen_rtx_PLUS (Pmode, temp, XEXP (x, 1));
+       }
     }
+
+  if (constant_term != const0_rtx)
+    x = gen_rtx_PLUS (Pmode, x, constant_term);
+
+  return x;
 }
 
+
 /* Output symbolic constant X in assembler syntax to 
    stdio stream FILE.  */
 
@@ -1417,11 +1572,11 @@ print_operand (file, x, code)
   switch (code)
     {
     case 'C':
-      output_branch_condition (file, x);
+      fprintf (file, s390_branch_condition_mnemonic (x, FALSE));
       return;
 
     case 'D':
-      output_inverse_branch_condition (file, x);
+      fprintf (file, s390_branch_condition_mnemonic (x, TRUE));
       return;
 
     case 'Y':
@@ -1806,7 +1961,7 @@ check_and_change_labels (insn, ltorg_uids)
      int *ltorg_uids;
 {
   rtx temp_reg = gen_rtx_REG (Pmode, RETURN_REGNUM);
-  rtx target, jump;
+  rtx target, jump, cjump;
   rtx pattern, tmp, body, label1;
   int addr0, addr1;
 
@@ -1878,7 +2033,10 @@ check_and_change_labels (insn, ltorg_uids)
                    }
                  
                  label1 = gen_label_rtx ();
-                 emit_jump_insn_before (gen_icjump (label1, XEXP (body, 0)), insn);
+                 cjump = gen_rtx_LABEL_REF (VOIDmode, label1);
+                 cjump = gen_rtx_IF_THEN_ELSE (VOIDmode, XEXP (body, 0), pc_rtx, cjump);
+                 cjump = gen_rtx_SET (VOIDmode, pc_rtx, cjump);
+                 emit_jump_insn_before (cjump, insn);
                  emit_insn_before (gen_movsi (temp_reg, target), insn);
                  tmp = emit_jump_insn_before (gen_indirect_jump (jump), insn);
                  INSN_ADDRESSES_NEW (emit_label_before (label1, insn), -1);
@@ -1912,7 +2070,10 @@ check_and_change_labels (insn, ltorg_uids)
                    }
                  
                  label1 = gen_label_rtx ();
-                 emit_jump_insn_before (gen_cjump (label1, XEXP (body, 0)), insn);
+                 cjump = gen_rtx_LABEL_REF (VOIDmode, label1);
+                 cjump = gen_rtx_IF_THEN_ELSE (VOIDmode, XEXP (body, 0), cjump, pc_rtx);
+                 cjump = gen_rtx_SET (VOIDmode, pc_rtx, cjump);
+                 emit_jump_insn_before (cjump, insn);
                  emit_insn_before (gen_movsi (temp_reg, target), insn);
                  tmp = emit_jump_insn_before (gen_indirect_jump (jump), insn);
                  INSN_ADDRESSES_NEW (emit_label_before (label1, insn), -1);
@@ -2541,8 +2702,7 @@ s390_function_prologue (file, lsize)
 
       /* Decrement stack.  */
 
-      if (TARGET_BACKCHAIN || (STARTING_FRAME_OFFSET +
-                              lsize + STACK_POINTER_OFFSET > 4095
+      if (TARGET_BACKCHAIN || (frame_size + STACK_POINTER_OFFSET > 4095
                               || frame_pointer_needed
                               || current_function_calls_alloca))
        {
@@ -2582,8 +2742,7 @@ s390_function_prologue (file, lsize)
 
       /* Generate backchain.  */
 
-      if (TARGET_BACKCHAIN || (STARTING_FRAME_OFFSET + 
-                              lsize + STACK_POINTER_OFFSET > 4095
+      if (TARGET_BACKCHAIN || (frame_size + STACK_POINTER_OFFSET > 4095
                               || frame_pointer_needed
                               || current_function_calls_alloca))
        {
index d250f05eb5fa7108b76d6224bf025d491c2d31be..90ba647ed49d850f314e63e0714a759f098e3391 100644 (file)
@@ -1687,6 +1687,7 @@ do {                                                                       \
 #define EXTRA_CC_MODES \
        CC (CCZmode, "CCZ") \
        CC (CCAmode, "CCA") \
+       CC (CCLmode, "CCL") \
        CC (CCUmode, "CCU") \
        CC (CCSmode, "CCS") \
        CC (CCTmode, "CCT")
@@ -1694,13 +1695,7 @@ do {                                                                       \
 /* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE,
    return the mode to be used for the comparison. */
  
-#define SELECT_CC_MODE(OP, X, Y)            \
- (   (OP) == EQ  || (OP) == NE  ? CCZmode   \
-   : (OP) == LE  || (OP) == LT  ||          \
-     (OP) == GE  || (OP) == GT  ? CCSmode   \
-   : (OP) == LEU || (OP) == LTU ||          \
-     (OP) == GEU || (OP) == GTU ? CCUmode   \
-   : CCmode )
+#define SELECT_CC_MODE(OP, X, Y) s390_select_ccmode ((OP), (X), (Y))
  
  
 /* Define the information needed to generate branch and scc insns.  This is
index 853ac9bcfc67eebb76a4c0ad5b370d1caf4c7daa..18e9c1c21c7832bf3cdf6e3880e5b40ca3ef4c72 100644 (file)
 
 (define_insn "*cmpsi_cct"
   [(set (reg 33)
-        (compare (zero_extract:SI (match_operand:SI 0 "register_operand" "%d")
+        (compare (zero_extract:SI (match_operand:SI 0 "register_operand" "d")
                          (match_operand:SI 1 "const1_operand" "")
                           (match_operand:SI 2 "immediate_operand"  "I"))
                  (const_int 0)))]
 
   if (flag_pic && SYMBOLIC_CONST (operands[1]))
     emit_pic_move (operands, SImode);
+
+  /* expr.c tries to load an effective address using 
+     force_reg.  This fails because we don't have a 
+     generic load_address pattern.  Convert the move
+     to a proper arithmetic operation instead, unless
+     it is guaranteed to be OK.  */
+  if (GET_CODE (operands[1]) == PLUS
+      && !legitimate_la_operand_p (operands[1]))
+    {
+      operands[1] = force_operand (operands[1], operands[0]);
+      if (operands[1] == operands[0])
+        DONE;
+    }
 }")
 
 (define_insn "*movsi"
 ; Compare a block that is less than 256 bytes in length.
 
 (define_insn "cmpstr_const"
-  [(set (reg:CCU 33)
-        (compare:CCU (match_operand:BLK 0 "s_operand" "oQ")
+  [(set (reg:CCS 33)
+        (compare:CCS (match_operand:BLK 0 "s_operand" "oQ")
                      (match_operand:BLK 1 "s_operand" "oQ")))
    (use (match_operand 2 "immediate_operand" "I"))]
   "(unsigned) INTVAL (operands[2]) < 256"
 ; Compare a block that is larger than 255 bytes in length.
 
 (define_insn "cmpstr_64"
-  [(set (reg:CCU 33)
-        (compare:CCU (mem:BLK (subreg:DI (match_operand:TI 0 "register_operand" "d") 0))
+  [(set (reg:CCS 33)
+        (compare:CCS (mem:BLK (subreg:DI (match_operand:TI 0 "register_operand" "d") 0))
                      (mem:BLK (subreg:DI (match_operand:TI 1 "register_operand" "d") 0))))
    (clobber (subreg:DI (match_dup 0) 0))
    (clobber (subreg:DI (match_dup 0) 8))
    (set_attr "type"    "other")])
 
 (define_insn "cmpstr_31"
-  [(set (reg:CCU 33)
-        (compare:CCU (mem:BLK (subreg:SI (match_operand:DI 0 "register_operand" "d") 0))
+  [(set (reg:CCS 33)
+        (compare:CCS (mem:BLK (subreg:SI (match_operand:DI 0 "register_operand" "d") 0))
                      (mem:BLK (subreg:SI (match_operand:DI 1 "register_operand" "d") 0))))
    (clobber (subreg:SI (match_dup 0) 0))
    (clobber (subreg:SI (match_dup 0) 4))
 
 (define_insn "cmpint_si"
   [(set (match_operand:SI 0 "register_operand" "=d")
-        (compare:SI (reg:CCU 33) (const_int 0)))]
+        (compare:SI (reg:CCS 33) (const_int 0)))]
   ""
   "*
 {
 
 (define_insn "cmpint_di"
   [(set (match_operand:DI 0 "register_operand" "=d")
-        (compare:DI (reg:CCU 33) (const_int 0)))]
+        (compare:DI (reg:CCS 33) (const_int 0)))]
   "TARGET_64BIT"
   "*
 {
    (set_attr "atype"    "mem")
    (set_attr "type"     "la")])
 
-(define_insn "*addaddr_picR"
-  [(set (match_operand:SI 0 "register_operand" "=d")
-        (plus:SI (match_operand:SI 1 "register_operand" "a")
-                 (unspec:SI [(match_operand:SI 2 "register_operand" "a")] 101)))]
-  ""
-  "la\\t%0,0(%1,%2)"
-  [(set_attr "op_type"  "RX")
-   (set_attr "atype"    "mem")
-   (set_attr "type"     "la")])
-
-(define_insn "*addaddr_picL"
-  [(set (match_operand:SI 0 "register_operand" "=d")
-        (plus:SI (unspec:SI [(match_operand:SI 2 "register_operand" "a")] 101)
-                 (match_operand:SI 1 "register_operand" "a")))]
-  ""
-  "la\\t%0,0(%1,%2)"
-  [(set_attr "op_type"  "RX")
-   (set_attr "atype"    "mem")
-   (set_attr "type"     "la")])
-
-(define_insn "*addaddr_picN"
-  [(set (match_operand:SI 0 "register_operand" "=d")
-        (unspec:SI [(match_operand:SI 1 "register_operand" "a")] 101))]
-  ""
-  "la\\t%0,0(%1)"
-  [(set_attr "op_type"  "RX")
-   (set_attr "atype"    "mem")
-   (set_attr "type"     "la")])
-
 (define_insn "*addsi3_cc"
   [(set (reg 33) 
-        (compare (plus:SI (match_operand:SI 1 "register_operand" "%0,0,0")
-                          (match_operand:SI 2 "general_operand" "d,K,m"))
+        (compare (plus:SI (match_operand:SI 1 "register_operand" "%0,0")
+                          (match_operand:SI 2 "nonimmediate_operand" "d,m"))
                  (const_int 0)))
-   (set (match_operand:SI 0 "register_operand" "=d,d,d")
+   (set (match_operand:SI 0 "register_operand" "=d,d")
         (plus:SI (match_dup 1) (match_dup 2)))]
-  "s390_match_ccmode(insn, CCSmode)"
+  "s390_match_ccmode(insn, CCLmode)"
   "@
-   ar\\t%0,%2
-   ahi\\t%0,%h2
-   a\\t%0,%2"
-  [(set_attr "op_type"  "RR,RI,RX")
-   (set_attr "atype"    "reg,reg,mem")])  
+   alr\\t%0,%2
+   al\\t%0,%2"
+  [(set_attr "op_type"  "RR,RX")
+   (set_attr "atype"    "reg,mem")])  
 
 (define_insn "*addsi3_cconly"
   [(set (reg 33) 
-        (compare (plus:SI (match_operand:SI 1 "register_operand" "%0,0,0")
-                          (match_operand:SI 2 "general_operand" "d,K,m"))
+        (compare (plus:SI (match_operand:SI 1 "register_operand" "%0,0")
+                          (match_operand:SI 2 "general_operand" "d,m"))
                  (const_int 0)))
-   (clobber (match_scratch:SI 0 "=d,d,d"))]
-  "s390_match_ccmode(insn, CCSmode)"
+   (clobber (match_scratch:SI 0 "=d,d"))]
+  "s390_match_ccmode(insn, CCLmode)"
   "@
-   ar\\t%0,%2
-   ahi\\t%0,%h2
-   a\\t%0,%2"
-  [(set_attr "op_type"  "RR,RI,RX")
-   (set_attr "atype"    "reg,reg,mem")])  
+   alr\\t%0,%2
+   al\\t%0,%2"
+  [(set_attr "op_type"  "RR,RX")
+   (set_attr "atype"    "reg,mem")])  
 
 (define_insn "*addsi3_cconly2"
   [(set (reg 33) 
-        (compare (match_operand:SI 1 "register_operand" "%0,0,0")
-                 (neg:SI (match_operand:SI 2 "general_operand" "d,K,m"))))
-   (clobber (match_scratch:SI 0 "=d,d,d"))]
-  "s390_match_ccmode(insn, CCSmode)"
+        (compare (match_operand:SI 1 "register_operand" "%0,0")
+                 (neg:SI (match_operand:SI 2 "general_operand" "d,m"))))
+   (clobber (match_scratch:SI 0 "=d,d"))]
+  "s390_match_ccmode(insn, CCLmode)"
   "@
-   ar\\t%0,%2
-   ahi\\t%0,%h2
-   a\\t%0,%2"
-  [(set_attr "op_type"  "RR,RI,RX")
-   (set_attr "atype"    "reg,reg,mem")])  
+   alr\\t%0,%2
+   al\\t%0,%2"
+  [(set_attr "op_type"  "RR,RX")
+   (set_attr "atype"    "reg,mem")])  
 
 (define_insn "addsi3"
   [(set (match_operand:SI 0 "register_operand" "=d,d,d")
   [(set_attr "op_type"  "RR,RI,RX")
    (set_attr "atype"    "reg,reg,mem")])
 
-(define_insn "do_la"
+(define_insn "*do_la"
   [(set (match_operand:SI 0 "register_operand" "=a")
         (match_operand:QI 1 "address_operand" "p"))]
-  "volatile_ok"
+  "reload_in_progress || reload_completed
+   || legitimate_la_operand_p (operands[1])"
   "la\\t%0,%a1"
   [(set_attr "op_type"  "RX")
    (set_attr "atype"    "mem")
   [(set (match_operand:SI 0 "register_operand" "=d")
         (plus:SI (match_operand:SI 1 "register_operand" "%0")
                  (match_operand:SI 2 "register_operand" "d")))]
-  ""
+  "reload_in_progress || reload_completed"
   "brxle\\t%0,%2,.+4"
   [(set_attr "op_type" "RSI")
    (set_attr "atype"   "reg")])
                  (const_int 0)))
    (set (match_operand:SI 0 "register_operand" "=d,d")
         (minus:SI (match_dup 1) (match_dup 2)))]
-  "s390_match_ccmode(insn, CCSmode)"
+  "s390_match_ccmode(insn, CCLmode)"
   "@
-   sr\\t%0,%2
-   s\\t%0,%2"
+   slr\\t%0,%2
+   sl\\t%0,%2"
   [(set_attr "op_type"  "RR,RX")
    (set_attr "atype"    "reg,mem")])
 
                            (match_operand:SI 2 "general_operand" "d,m"))
                  (const_int 0)))
    (clobber (match_scratch:SI 0 "=d,d"))]
-  "s390_match_ccmode(insn, CCSmode)"
+  "s390_match_ccmode(insn, CCLmode)"
   "@
-   sr\\t%0,%2
-   s\\t%0,%2"
+   slr\\t%0,%2
+   sl\\t%0,%2"
   [(set_attr "op_type"  "RR,RX")
    (set_attr "atype"    "reg,mem")])
 
   ""
   "{ operands[1] = s390_compare_op0; operands[2] = s390_compare_op1; }")
 
+(define_expand "bunordered"
+  [(set (reg:CCS 33) (compare:CCS (match_dup 1) (match_dup 2)))
+   (set (pc)
+        (if_then_else (unordered (reg:CCS 33) (const_int 0))
+                      (label_ref (match_operand 0 "" ""))
+                      (pc)))]
+  ""
+  "{ operands[1] = s390_compare_op0; operands[2] = s390_compare_op1; }")
+
+(define_expand "bordered"
+  [(set (reg:CCS 33) (compare:CCS (match_dup 1) (match_dup 2)))
+   (set (pc)
+        (if_then_else (ordered (reg:CCS 33) (const_int 0))
+                      (label_ref (match_operand 0 "" ""))
+                      (pc)))]
+  ""
+  "{ operands[1] = s390_compare_op0; operands[2] = s390_compare_op1; }")
+
+(define_expand "buneq"
+  [(set (reg:CCS 33) (compare:CCS (match_dup 1) (match_dup 2)))
+   (set (pc)
+        (if_then_else (uneq (reg:CCS 33) (const_int 0))
+                      (label_ref (match_operand 0 "" ""))
+                      (pc)))]
+  ""
+  "{ operands[1] = s390_compare_op0; operands[2] = s390_compare_op1; }")
+
+(define_expand "bungt"
+  [(set (reg:CCS 33) (compare:CCS (match_dup 1) (match_dup 2)))
+   (set (pc)
+        (if_then_else (ungt (reg:CCS 33) (const_int 0))
+                      (label_ref (match_operand 0 "" ""))
+                      (pc)))]
+  ""
+  "{ operands[1] = s390_compare_op0; operands[2] = s390_compare_op1; }")
+
+(define_expand "bunlt"
+  [(set (reg:CCS 33) (compare:CCS (match_dup 1) (match_dup 2)))
+   (set (pc)
+        (if_then_else (unlt (reg:CCS 33) (const_int 0))
+                      (label_ref (match_operand 0 "" ""))
+                      (pc)))]
+  ""
+  "{ operands[1] = s390_compare_op0; operands[2] = s390_compare_op1; }")
+
+(define_expand "bunge"
+  [(set (reg:CCS 33) (compare:CCS (match_dup 1) (match_dup 2)))
+   (set (pc)
+        (if_then_else (unge (reg:CCS 33) (const_int 0))
+                      (label_ref (match_operand 0 "" ""))
+                      (pc)))]
+  ""
+  "{ operands[1] = s390_compare_op0; operands[2] = s390_compare_op1; }")
+
+(define_expand "bunle"
+  [(set (reg:CCS 33) (compare:CCS (match_dup 1) (match_dup 2)))
+   (set (pc)
+        (if_then_else (unle (reg:CCS 33) (const_int 0))
+                      (label_ref (match_operand 0 "" ""))
+                      (pc)))]
+  ""
+  "{ operands[1] = s390_compare_op0; operands[2] = s390_compare_op1; }")
+
+(define_expand "bltgt"
+  [(set (reg:CCS 33) (compare:CCS (match_dup 1) (match_dup 2)))
+   (set (pc)
+        (if_then_else (ltgt (reg:CCS 33) (const_int 0))
+                      (label_ref (match_operand 0 "" ""))
+                      (pc)))]
+  ""
+  "{ operands[1] = s390_compare_op0; operands[2] = s390_compare_op1; }")
+
 
 ;;
 ;;- Conditional jump instructions.