OSDN Git Service

* config/i386/i386.md (ashlti3, ashrti3, lshrti3): Expand using
[pf3gnuchains/gcc-fork.git] / gcc / config / i386 / predicates.md
index 457f556..f36c6d4 100644 (file)
@@ -1,11 +1,11 @@
 ;; Predicate definitions for IA-32 and x86-64.
-;; Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
+;; Copyright (C) 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
 ;;
 ;; This file is part of GCC.
 ;;
 ;; GCC is free software; you can redistribute it and/or modify
 ;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 2, or (at your option)
+;; the Free Software Foundation; either version 3, or (at your option)
 ;; any later version.
 ;;
 ;; GCC is distributed in the hope that it will be useful,
@@ -14,9 +14,8 @@
 ;; GNU General Public License for more details.
 ;;
 ;; You should have received a copy of the GNU General Public License
-;; along with GCC; see the file COPYING.  If not, write to
-;; the Free Software Foundation, 51 Franklin Street, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
+;; along with GCC; see the file COPYING3.  If not see
+;; <http://www.gnu.org/licenses/>.
 
 ;; Return nonzero if OP is either a i387 or SSE fp register.
 (define_predicate "any_fp_register_operand"
   return ANY_QI_REG_P (op);
 })
 
-;; Return true if op is a NON_Q_REGS class register.
-(define_predicate "non_q_regs_operand"
-  (match_operand 0 "register_operand")
-{
-  if (GET_CODE (op) == SUBREG)
-    op = SUBREG_REG (op);
-  return NON_QI_REG_P (op);
-})
-
 ;; Match an SI or HImode register for a zero_extract.
 (define_special_predicate "ext_register_operand"
   (match_operand 0 "register_operand")
   (and (match_code "reg")
        (match_test "REGNO (op) == FLAGS_REG")))
 
+;; Return true if op is not xmm0 register.
+(define_predicate "reg_not_xmm0_operand"
+   (and (match_operand 0 "register_operand")
+       (match_test "GET_CODE (op) != REG
+                    || REGNO (op) != FIRST_SSE_REG")))
+
+;; As above, but allow nonimmediate operands.
+(define_predicate "nonimm_not_xmm0_operand"
+   (and (match_operand 0 "nonimmediate_operand")
+       (match_test "GET_CODE (op) != REG
+                    || REGNO (op) != FIRST_SSE_REG")))
+
 ;; Return 1 if VALUE can be stored in a sign extended immediate field.
 (define_predicate "x86_64_immediate_operand"
   (match_code "const_int,symbol_ref,label_ref,const")
 
          if (ix86_cmodel == CM_LARGE)
            return 0;
-         if (GET_CODE (op2) != CONST_INT)
+         if (!CONST_INT_P (op2))
            return 0;
          offset = trunc_int_for_mode (INTVAL (op2), DImode);
          switch (GET_CODE (op1))
              if ((ix86_cmodel == CM_SMALL
                   || (ix86_cmodel == CM_MEDIUM
                       && !SYMBOL_REF_FAR_ADDR_P (op1)))
-                 && GET_CODE (op2) == CONST_INT
+                 && CONST_INT_P (op2)
                  && trunc_int_for_mode (INTVAL (op2), DImode) > -0x10000
                  && trunc_int_for_mode (INTVAL (op2), SImode) == INTVAL (op2))
                return 1;
              /* These conditions are similar to SYMBOL_REF ones, just the
                 constraints for code models differ.  */
              if ((ix86_cmodel == CM_SMALL || ix86_cmodel == CM_MEDIUM)
-                 && GET_CODE (op2) == CONST_INT
+                 && CONST_INT_P (op2)
                  && trunc_int_for_mode (INTVAL (op2), DImode) > -0x10000
                  && trunc_int_for_mode (INTVAL (op2), SImode) == INTVAL (op2))
                return 1;
   if (TARGET_64BIT && GET_CODE (op) == CONST)
     {
       op = XEXP (op, 0);
-      if (GET_CODE (op) == PLUS && GET_CODE (XEXP (op, 1)) == CONST_INT)
+      if (GET_CODE (op) == PLUS && CONST_INT_P (XEXP (op, 1)))
        op = XEXP (op, 0);
       if (GET_CODE (op) == UNSPEC
          && (XINT (op, 1) == UNSPEC_GOTOFF
                  || XINT (op, 1) == UNSPEC_GOTPCREL)))
        return 1;
       if (GET_CODE (op) != PLUS
-         || GET_CODE (XEXP (op, 1)) != CONST_INT)
+         || !CONST_INT_P (XEXP (op, 1)))
        return 0;
 
       op = XEXP (op, 0);
       if (GET_CODE (op) == UNSPEC)
        return 1;
       if (GET_CODE (op) != PLUS
-         || GET_CODE (XEXP (op, 1)) != CONST_INT)
+         || !CONST_INT_P (XEXP (op, 1)))
        return 0;
       op = XEXP (op, 0);
       if (GET_CODE (op) == UNSPEC)
 {
   if (GET_CODE (op) == CONST
       && GET_CODE (XEXP (op, 0)) == PLUS
-      && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT)
+      && CONST_INT_P (XEXP (XEXP (op, 0), 1)))
     op = XEXP (XEXP (op, 0), 0);
 
   if (GET_CODE (op) == LABEL_REF)
   if (GET_CODE (op) != SYMBOL_REF)
     return 0;
 
+  if (SYMBOL_REF_TLS_MODEL (op) != 0)
+    return 0;
+
   if (SYMBOL_REF_LOCAL_P (op))
     return 1;
 
   return 0;
 })
 
+;; Test for a legitimate @GOTOFF operand.
+;;
+;; VxWorks does not impose a fixed gap between segments; the run-time
+;; gap can be different from the object-file gap.  We therefore can't
+;; use @GOTOFF unless we are absolutely sure that the symbol is in the
+;; same segment as the GOT.  Unfortunately, the flexibility of linker
+;; scripts means that we can't be sure of that in general, so assume
+;; that @GOTOFF is never valid on VxWorks.
+(define_predicate "gotoff_operand"
+  (and (match_test "!TARGET_VXWORKS_RTP")
+       (match_operand 0 "local_symbolic_operand")))
+
 ;; Test for various thread-local symbols.
 (define_predicate "tls_symbolic_operand"
   (and (match_code "symbol_ref")
 
 ;; Test for a pc-relative call operand
 (define_predicate "constant_call_address_operand"
-  (ior (match_code "symbol_ref")
-       (match_operand 0 "local_symbolic_operand")))
+  (match_code "symbol_ref")
+{
+  if (ix86_cmodel == CM_LARGE || ix86_cmodel == CM_LARGE_PIC)
+    return false;
+  if (TARGET_DLLIMPORT_DECL_ATTRIBUTES && SYMBOL_REF_DLLIMPORT_P (op))
+    return false;
+  return true;
+})
 
 ;; True for any non-virtual or eliminable register.  Used in places where
 ;; instantiation of such a register may cause the pattern to not be recognized.
     op = SUBREG_REG (op);
   return !(op == arg_pointer_rtx
           || op == frame_pointer_rtx
-          || (REGNO (op) >= FIRST_PSEUDO_REGISTER
-              && REGNO (op) <= LAST_VIRTUAL_REGISTER));
+          || IN_RANGE (REGNO (op),
+                       FIRST_PSEUDO_REGISTER, LAST_VIRTUAL_REGISTER));
 })
 
 ;; Similarly, but include the stack pointer.  This is used to prevent esp
 ;; Match 0 to 3.
 (define_predicate "const_0_to_3_operand"
   (and (match_code "const_int")
-       (match_test "INTVAL (op) >= 0 && INTVAL (op) <= 3")))
+       (match_test "IN_RANGE (INTVAL (op), 0, 3)")))
 
 ;; Match 0 to 7.
 (define_predicate "const_0_to_7_operand"
   (and (match_code "const_int")
-       (match_test "INTVAL (op) >= 0 && INTVAL (op) <= 7")))
+       (match_test "IN_RANGE (INTVAL (op), 0, 7)")))
 
 ;; Match 0 to 15.
 (define_predicate "const_0_to_15_operand"
   (and (match_code "const_int")
-       (match_test "INTVAL (op) >= 0 && INTVAL (op) <= 15")))
+       (match_test "IN_RANGE (INTVAL (op), 0, 15)")))
+
+;; Match 0 to 31.
+(define_predicate "const_0_to_31_operand"
+  (and (match_code "const_int")
+       (match_test "IN_RANGE (INTVAL (op), 0, 31)")))
 
 ;; Match 0 to 63.
 (define_predicate "const_0_to_63_operand"
   (and (match_code "const_int")
-       (match_test "INTVAL (op) >= 0 && INTVAL (op) <= 63")))
+       (match_test "IN_RANGE (INTVAL (op), 0, 63)")))
 
 ;; Match 0 to 255.
 (define_predicate "const_0_to_255_operand"
   (and (match_code "const_int")
-       (match_test "INTVAL (op) >= 0 && INTVAL (op) <= 255")))
+       (match_test "IN_RANGE (INTVAL (op), 0, 255)")))
 
 ;; Match (0 to 255) * 8
 (define_predicate "const_0_to_255_mul_8_operand"
 ;; for shift & compare patterns, as shifting by 0 does not change flags).
 (define_predicate "const_1_to_31_operand"
   (and (match_code "const_int")
-       (match_test "INTVAL (op) >= 1 && INTVAL (op) <= 31")))
+       (match_test "IN_RANGE (INTVAL (op), 1, 31)")))
+
+;; Return nonzero if OP is CONST_INT >= 1 and <= 63 (a valid operand
+;; for 64bit shift & compare patterns, as shifting by 0 does not change flags).
+(define_predicate "const_1_to_63_operand"
+  (and (match_code "const_int")
+       (match_test "IN_RANGE (INTVAL (op), 1, 63)")))
 
 ;; Match 2 or 3.
 (define_predicate "const_2_to_3_operand"
   (and (match_code "const_int")
-       (match_test "INTVAL (op) == 2 || INTVAL (op) == 3")))
+       (match_test "IN_RANGE (INTVAL (op), 2, 3)")))
 
 ;; Match 4 to 7.
 (define_predicate "const_4_to_7_operand"
   (and (match_code "const_int")
-       (match_test "INTVAL (op) >= 4 && INTVAL (op) <= 7")))
+       (match_test "IN_RANGE (INTVAL (op), 4, 7)")))
+
+;; Match exactly one bit in 2-bit mask.
+(define_predicate "const_pow2_1_to_2_operand"
+  (and (match_code "const_int")
+       (match_test "INTVAL (op) == 1 || INTVAL (op) == 2")))
 
 ;; Match exactly one bit in 4-bit mask.
 (define_predicate "const_pow2_1_to_8_operand"
   return log <= 7;
 })
 
+;; Match exactly one bit in 16-bit mask.
+(define_predicate "const_pow2_1_to_32768_operand"
+  (match_code "const_int")
+{
+  unsigned int log = exact_log2 (INTVAL (op));
+  return log <= 15;
+})
+
 ;; True if this is a constant appropriate for an increment or decrement.
 (define_predicate "incdec_operand"
   (match_code "const_int")
     }
   if (parts.disp)
     {
-      if (GET_CODE (parts.disp) != CONST_INT
+      if (!CONST_INT_P (parts.disp)
          || (INTVAL (parts.disp) & 3) != 0)
        return 0;
     }
   switch (code)
     {
     case LTU: case GTU: case LEU: case GEU:
-      if (inmode == CCmode || inmode == CCFPmode || inmode == CCFPUmode)
+      if (inmode == CCmode || inmode == CCFPmode || inmode == CCFPUmode
+         || inmode == CCCmode)
        return 1;
       return 0;
     case ORDERED: case UNORDERED:
 (define_special_predicate "sse_comparison_operator"
   (match_code "eq,lt,le,unordered,ne,unge,ungt,ordered"))
 
+;; Return 1 if OP is a comparison operator that can be issued by sse predicate
+;; generation instructions
+(define_predicate "sse5_comparison_float_operator"
+  (and (match_test "TARGET_SSE5")
+       (match_code "ne,eq,ge,gt,le,lt,unordered,ordered,uneq,unge,ungt,unle,unlt,ltgt")))
+
+(define_predicate "ix86_comparison_int_operator"
+  (match_code "ne,eq,ge,gt,le,lt"))
+
+(define_predicate "ix86_comparison_uns_operator"
+  (match_code "ne,eq,geu,gtu,leu,ltu"))
+
+(define_predicate "bt_comparison_operator"
+  (match_code "ne,eq"))
+
 ;; Return 1 if OP is a valid comparison operator in valid mode.
 (define_predicate "ix86_comparison_operator"
   (match_operand 0 "comparison_operator")
          || inmode == CCGOCmode || inmode == CCNOmode)
        return 1;
       return 0;
-    case LTU: case GTU: case LEU: case ORDERED: case UNORDERED: case GEU:
+    case LTU: case GTU: case LEU: case GEU:
+      if (inmode == CCmode || inmode == CCCmode)
+       return 1;
+      return 0;
+    case ORDERED: case UNORDERED:
       if (inmode == CCmode)
        return 1;
       return 0;
 
 ;; Return 1 if OP is a valid comparison operator testing carry flag to be set.
 (define_predicate "ix86_carry_flag_operator"
-  (match_code "ltu,lt,unlt,gt,ungt,le,unle,ge,unge,ltgt,uneq")
+  (match_code "ltu,lt,unlt,gtu,gt,ungt,le,unle,ge,unge,ltgt,uneq")
 {
   enum machine_mode inmode = GET_MODE (XEXP (op, 0));
   enum rtx_code code = GET_CODE (op);
 
-  if (GET_CODE (XEXP (op, 0)) != REG
+  if (!REG_P (XEXP (op, 0))
       || REGNO (XEXP (op, 0)) != FLAGS_REG
       || XEXP (op, 1) != const0_rtx)
     return 0;
        return 0;
       code = ix86_fp_compare_code_to_integer (code);
     }
+  else if (inmode == CCCmode)
+   return code == LTU || code == GTU;
   else if (inmode != CCmode)
     return 0;
 
               mod,udiv,umod,ashift,rotate,ashiftrt,lshiftrt,rotatert"))
 
 ;; Return 1 if OP is a binary operator that can be promoted to wider mode.
-;; Modern CPUs have same latency for HImode and SImode multiply,
-;; but 386 and 486 do HImode multiply faster.  */
 (define_predicate "promotable_binary_operator"
   (ior (match_code "plus,and,ior,xor,ashift")
        (and (match_code "mult")
-           (match_test "ix86_tune > PROCESSOR_I486"))))
+           (match_test "TARGET_TUNE_PROMOTE_HIMODE_IMUL"))))
 
 ;; To avoid problems when jump re-emits comparisons like testqi_ext_ccno_0,
 ;; re-recognize the operand to avoid a copy_to_mode_reg that will fail.
 
 (define_predicate "absneg_operator"
   (match_code "abs,neg"))
+
+;; Return 1 if OP is misaligned memory operand
+(define_predicate "misaligned_operand"
+  (and (match_code "mem")
+       (match_test "MEM_ALIGN (op) < GET_MODE_ALIGNMENT (mode)")))