OSDN Git Service

Backported from mainline
[pf3gnuchains/gcc-fork.git] / gcc / config / i386 / i386.md
index ef9a76d..f09717d 100644 (file)
   UNSPEC_CALL_NEEDS_VZEROUPPER
   UNSPEC_PAUSE
   UNSPEC_LEA_ADDR
+  UNSPEC_STOS
 
   ;; For SSE/MMX support:
   UNSPEC_FIX_NOTRUNC
 
   ;; For RDRAND support
   UNSPECV_RDRAND
-])
+
+  ;; Non-local goto.
+  UNSPECV_NLGR
+ ])
 
 ;; Constants to represent rounding modes in the ROUND instruction
 (define_constants
   split_double_mode (DImode, &operands[1], 1, &operands[2], &operands[3]);
 
   operands[1] = gen_lowpart (DImode, operands[2]);
-  operands[2] = gen_rtx_MEM (SImode, gen_rtx_PLUS (DImode, stack_pointer_rtx,
+  operands[2] = gen_rtx_MEM (SImode, gen_rtx_PLUS (Pmode, stack_pointer_rtx,
                                                   GEN_INT (4)));
 })
 
   split_double_mode (DImode, &operands[1], 1, &operands[2], &operands[3]);
 
   operands[1] = gen_lowpart (DImode, operands[2]);
-  operands[2] = gen_rtx_MEM (SImode, gen_rtx_PLUS (DImode, stack_pointer_rtx,
+  operands[2] = gen_rtx_MEM (SImode, gen_rtx_PLUS (Pmode, stack_pointer_rtx,
                                                   GEN_INT (4)));
 })
 
   [(set_attr "type" "*,*,sselog1,ssemov,ssemov")
    (set_attr "prefix" "*,*,maybe_vex,maybe_vex,maybe_vex")
    (set (attr "mode")
-       (cond [(eq_attr "alternative" "2,3")
-                (if_then_else
-                  (match_test "optimize_function_for_size_p (cfun)")
-                  (const_string "V4SF")
-                  (const_string "TI"))
-              (eq_attr "alternative" "4")
-                (if_then_else
-                  (ior (match_test "TARGET_SSE_TYPELESS_STORES")
-                       (match_test "optimize_function_for_size_p (cfun)"))
-                  (const_string "V4SF")
-                  (const_string "TI"))]
-              (const_string "DI")))])
+       (cond [(eq_attr "alternative" "0,1")
+                (const_string "DI")
+              (ior (not (match_test "TARGET_SSE2"))
+                   (match_test "optimize_function_for_size_p (cfun)"))
+                (const_string "V4SF")
+              (and (eq_attr "alternative" "4")
+                   (match_test "TARGET_SSE_TYPELESS_STORES"))
+                (const_string "V4SF")
+              ]
+              (const_string "TI")))])
 
 (define_split
   [(set (match_operand:TI 0 "nonimmediate_operand" "")
   "TARGET_LP64 && ix86_check_movabs (insn, 0)"
   "@
    movabs{<imodesuffix>}\t{%1, %P0|[%P0], %1}
-   mov{<imodesuffix>}\t{%1, %a0|%a0, %1}"
+   mov{<imodesuffix>}\t{%1, %a0|<iptrsize> PTR %a0, %1}"
   [(set_attr "type" "imov")
    (set_attr "modrm" "0,*")
    (set_attr "length_address" "8,0")
   "TARGET_LP64 && ix86_check_movabs (insn, 1)"
   "@
    movabs{<imodesuffix>}\t{%P1, %0|%0, [%P1]}
-   mov{<imodesuffix>}\t{%a1, %0|%0, %a1}"
+   mov{<imodesuffix>}\t{%a1, %0|%0, <iptrsize> PTR %a1}"
   [(set_attr "type" "imov")
    (set_attr "modrm" "0,*")
    (set_attr "length_address" "8,0")
 })
 
 (define_insn "*zero_extendsidi2_rex64"
-  [(set (match_operand:DI 0 "nonimmediate_operand"  "=r,o,?*Ym,?*y,?*Yi,*x")
+  [(set (match_operand:DI 0 "nonimmediate_operand"  "=r,o,?*Ym,?!*y,?*Yi,*x")
        (zero_extend:DI
-        (match_operand:SI 1 "nonimmediate_operand" "rm,0,r   ,m  ,r   ,m")))]
+        (match_operand:SI 1 "nonimmediate_operand" "rm,0,r   ,m   ,r   ,m")))]
   "TARGET_64BIT"
   "@
    mov{l}\t{%1, %k0|%k0, %1}
 
 ;; %%% Kill me once multi-word ops are sane.
 (define_insn "zero_extendsidi2_1"
-  [(set (match_operand:DI 0 "nonimmediate_operand" "=r,?r,?o,?*Ym,?*y,?*Yi,*x")
+  [(set (match_operand:DI 0 "nonimmediate_operand" "=r,?r,?o,?*Ym,?!*y,?*Yi,*x")
        (zero_extend:DI
-        (match_operand:SI 1 "nonimmediate_operand" "0,rm,r ,r   ,m  ,r   ,m")))
+        (match_operand:SI 1 "nonimmediate_operand" "0,rm,r ,r   ,m   ,r   ,m")))
    (clobber (reg:CC FLAGS_REG))]
   "!TARGET_64BIT"
   "@
    (set_attr "pent_pair" "pu")
    (set_attr "mode" "SI")])
 \f
-;; Overflow setting add and subtract instructions
+;; Overflow setting add instructions
 
 (define_insn "*add<mode>3_cconly_overflow"
   [(set (reg:CCC FLAGS_REG)
   [(set_attr "type" "alu")
    (set_attr "mode" "<MODE>")])
 
-(define_insn "*sub<mode>3_cconly_overflow"
-  [(set (reg:CCC FLAGS_REG)
-       (compare:CCC
-         (minus:SWI
-           (match_operand:SWI 0 "nonimmediate_operand" "<r>m,<r>")
-           (match_operand:SWI 1 "<general_operand>" "<r><i>,<r>m"))
-         (match_dup 0)))]
-  ""
-  "cmp{<imodesuffix>}\t{%1, %0|%0, %1}"
-  [(set_attr "type" "icmp")
-   (set_attr "mode" "<MODE>")])
-
-(define_insn "*<plusminus_insn><mode>3_cc_overflow"
+(define_insn "*add<mode>3_cc_overflow"
   [(set (reg:CCC FLAGS_REG)
        (compare:CCC
-           (plusminus:SWI
-               (match_operand:SWI 1 "nonimmediate_operand" "<comm>0,0")
+           (plus:SWI
+               (match_operand:SWI 1 "nonimmediate_operand" "%0,0")
                (match_operand:SWI 2 "<general_operand>" "<r><i>,<r>m"))
            (match_dup 1)))
    (set (match_operand:SWI 0 "nonimmediate_operand" "=<r>m,<r>")
-       (plusminus:SWI (match_dup 1) (match_dup 2)))]
-  "ix86_binary_operator_ok (<CODE>, <MODE>mode, operands)"
-  "<plusminus_mnemonic>{<imodesuffix>}\t{%2, %0|%0, %2}"
+       (plus:SWI (match_dup 1) (match_dup 2)))]
+  "ix86_binary_operator_ok (PLUS, <MODE>mode, operands)"
+  "add{<imodesuffix>}\t{%2, %0|%0, %2}"
   [(set_attr "type" "alu")
    (set_attr "mode" "<MODE>")])
 
-(define_insn "*<plusminus_insn>si3_zext_cc_overflow"
+(define_insn "*addsi3_zext_cc_overflow"
   [(set (reg:CCC FLAGS_REG)
        (compare:CCC
-         (plusminus:SI
-           (match_operand:SI 1 "nonimmediate_operand" "<comm>0")
+         (plus:SI
+           (match_operand:SI 1 "nonimmediate_operand" "%0")
            (match_operand:SI 2 "x86_64_general_operand" "rme"))
          (match_dup 1)))
    (set (match_operand:DI 0 "register_operand" "=r")
-       (zero_extend:DI (plusminus:SI (match_dup 1) (match_dup 2))))]
-  "TARGET_64BIT && ix86_binary_operator_ok (<CODE>, SImode, operands)"
-  "<plusminus_mnemonic>{l}\t{%2, %k0|%k0, %2}"
+       (zero_extend:DI (plus:SI (match_dup 1) (match_dup 2))))]
+  "TARGET_64BIT && ix86_binary_operator_ok (PLUS, SImode, operands)"
+  "add{l}\t{%2, %k0|%k0, %2}"
   [(set_attr "type" "alu")
    (set_attr "mode" "SI")])
 
         (const_int 0)))
    (set (match_operand:DI 0 "nonimmediate_operand" "=r,r,rm")
        (and:DI (match_dup 1) (match_dup 2)))]
-  "TARGET_64BIT && ix86_match_ccmode (insn, CCNOmode)
+  "TARGET_64BIT
+   && ix86_match_ccmode
+       (insn,
+        /* If we are going to emit andl instead of andq, and the operands[2]
+           constant might have the SImode sign bit set, make sure the sign
+           flag isn't tested, because the instruction will set the sign flag
+           based on bit 31 rather than bit 63.  If it isn't CONST_INT,
+           conservatively assume it might have bit 31 set.  */
+        (satisfies_constraint_Z (operands[2])
+         && (!CONST_INT_P (operands[2])
+             || val_signbit_known_set_p (SImode, INTVAL (operands[2]))))
+        ? CCZmode : CCNOmode)
    && ix86_binary_operator_ok (AND, DImode, operands)"
   "@
    and{l}\t{%k2, %k0|%k0, %k2}
 })
 
 ;; Avoid useless masking of count operand.
-(define_insn_and_split "*ashl<mode>3_mask"
+(define_insn "*ashl<mode>3_mask"
   [(set (match_operand:SWI48 0 "nonimmediate_operand" "=rm")
        (ashift:SWI48
          (match_operand:SWI48 1 "nonimmediate_operand" "0")
          (subreg:QI
            (and:SI
-             (match_operand:SI 2 "nonimmediate_operand" "c")
+             (match_operand:SI 2 "register_operand" "c")
              (match_operand:SI 3 "const_int_operand" "n")) 0)))
    (clobber (reg:CC FLAGS_REG))]
   "ix86_binary_operator_ok (ASHIFT, <MODE>mode, operands)
    && (INTVAL (operands[3]) & (GET_MODE_BITSIZE (<MODE>mode)-1))
       == GET_MODE_BITSIZE (<MODE>mode)-1"
-  "#"
-  "&& 1"
-  [(parallel [(set (match_dup 0)
-                  (ashift:SWI48 (match_dup 1) (match_dup 2)))
-             (clobber (reg:CC FLAGS_REG))])]
 {
-  if (can_create_pseudo_p ())
-    operands [2] = force_reg (SImode, operands[2]);
-
-  operands[2] = simplify_gen_subreg (QImode, operands[2], SImode, 0);
+  return "sal{<imodesuffix>}\t{%b2, %0|%0, %b2}";
 }
   [(set_attr "type" "ishift")
    (set_attr "mode" "<MODE>")])
   "ix86_expand_binary_operator (<CODE>, <MODE>mode, operands); DONE;")
 
 ;; Avoid useless masking of count operand.
-(define_insn_and_split "*<shift_insn><mode>3_mask"
+(define_insn "*<shift_insn><mode>3_mask"
   [(set (match_operand:SWI48 0 "nonimmediate_operand" "=rm")
        (any_shiftrt:SWI48
          (match_operand:SWI48 1 "nonimmediate_operand" "0")
          (subreg:QI
            (and:SI
-             (match_operand:SI 2 "nonimmediate_operand" "c")
+             (match_operand:SI 2 "register_operand" "c")
              (match_operand:SI 3 "const_int_operand" "n")) 0)))
    (clobber (reg:CC FLAGS_REG))]
   "ix86_binary_operator_ok (<CODE>, <MODE>mode, operands)
    && (INTVAL (operands[3]) & (GET_MODE_BITSIZE (<MODE>mode)-1))
       == GET_MODE_BITSIZE (<MODE>mode)-1"
-  "#"
-  "&& 1"
-  [(parallel [(set (match_dup 0)
-                  (any_shiftrt:SWI48 (match_dup 1) (match_dup 2)))
-             (clobber (reg:CC FLAGS_REG))])]
 {
-  if (can_create_pseudo_p ())
-    operands [2] = force_reg (SImode, operands[2]);
-
-  operands[2] = simplify_gen_subreg (QImode, operands[2], SImode, 0);
+  return "<shift>{<imodesuffix>}\t{%b2, %0|%0, %b2}";
 }
   [(set_attr "type" "ishift")
    (set_attr "mode" "<MODE>")])
   "ix86_expand_binary_operator (<CODE>, <MODE>mode, operands); DONE;")
 
 ;; Avoid useless masking of count operand.
-(define_insn_and_split "*<rotate_insn><mode>3_mask"
+(define_insn "*<rotate_insn><mode>3_mask"
   [(set (match_operand:SWI48 0 "nonimmediate_operand" "=rm")
        (any_rotate:SWI48
          (match_operand:SWI48 1 "nonimmediate_operand" "0")
          (subreg:QI
            (and:SI
-             (match_operand:SI 2 "nonimmediate_operand" "c")
+             (match_operand:SI 2 "register_operand" "c")
              (match_operand:SI 3 "const_int_operand" "n")) 0)))
    (clobber (reg:CC FLAGS_REG))]
   "ix86_binary_operator_ok (<CODE>, <MODE>mode, operands)
    && (INTVAL (operands[3]) & (GET_MODE_BITSIZE (<MODE>mode)-1))
       == GET_MODE_BITSIZE (<MODE>mode)-1"
-  "#"
-  "&& 1"
-  [(parallel [(set (match_dup 0)
-                  (any_rotate:SWI48 (match_dup 1) (match_dup 2)))
-             (clobber (reg:CC FLAGS_REG))])]
 {
-  if (can_create_pseudo_p ())
-    operands [2] = force_reg (SImode, operands[2]);
-
-  operands[2] = simplify_gen_subreg (QImode, operands[2], SImode, 0);
+  return "<rotate>{<imodesuffix>}\t{%b2, %0|%0, %b2}";
 }
   [(set_attr "type" "rotate")
    (set_attr "mode" "<MODE>")])
 
 (define_insn "bmi_bextr_<mode>"
   [(set (match_operand:SWI48 0 "register_operand" "=r")
-        (unspec:SWI48 [(match_operand:SWI48 1 "register_operand" "r")
-                       (match_operand:SWI48 2 "nonimmediate_operand" "rm")]
+        (unspec:SWI48 [(match_operand:SWI48 1 "nonimmediate_operand" "rm")
+                       (match_operand:SWI48 2 "register_operand" "r")]
                        UNSPEC_BEXTR))
    (clobber (reg:CC FLAGS_REG))]
   "TARGET_BMI"
 ;; BMI2 instructions.
 (define_insn "bmi2_bzhi_<mode>3"
   [(set (match_operand:SWI48 0 "register_operand" "=r")
-       (and:SWI48 (match_operand:SWI48 1 "register_operand" "r")
-                  (lshiftrt:SWI48 (const_int -1)
-                                  (match_operand:SWI48 2 "nonimmediate_operand" "rm"))))
+       (and:SWI48 (lshiftrt:SWI48 (const_int -1)
+                                  (match_operand:SWI48 2 "register_operand" "r"))
+                  (match_operand:SWI48 1 "nonimmediate_operand" "rm")))
    (clobber (reg:CC FLAGS_REG))]
   "TARGET_BMI2"
   "bzhi\t{%2, %1, %0|%0, %1, %2}"
   [(parallel [(set (match_operand 1 "memory_operand" "")
                   (match_operand 2 "register_operand" ""))
              (set (match_operand 0 "register_operand" "")
-                  (match_operand 3 "" ""))])]
+                  (match_operand 3 "" ""))
+             (unspec [(const_int 0)] UNSPEC_STOS)])]
   ""
   "ix86_current_function_needs_cld = 1;")
 
        (match_operand:DI 2 "register_operand" "a"))
    (set (match_operand:DI 0 "register_operand" "=D")
        (plus:DI (match_dup 1)
-                (const_int 8)))]
+                (const_int 8)))
+   (unspec [(const_int 0)] UNSPEC_STOS)]
   "TARGET_64BIT
    && !(fixed_regs[AX_REG] || fixed_regs[DI_REG])"
   "stosq"
        (match_operand:SI 2 "register_operand" "a"))
    (set (match_operand:P 0 "register_operand" "=D")
        (plus:P (match_dup 1)
-               (const_int 4)))]
+               (const_int 4)))
+   (unspec [(const_int 0)] UNSPEC_STOS)]
   "!(fixed_regs[AX_REG] || fixed_regs[DI_REG])"
   "stos{l|d}"
   [(set_attr "type" "str")
        (match_operand:HI 2 "register_operand" "a"))
    (set (match_operand:P 0 "register_operand" "=D")
        (plus:P (match_dup 1)
-               (const_int 2)))]
+               (const_int 2)))
+   (unspec [(const_int 0)] UNSPEC_STOS)]
   "!(fixed_regs[AX_REG] || fixed_regs[DI_REG])"
   "stosw"
   [(set_attr "type" "str")
        (match_operand:QI 2 "register_operand" "a"))
    (set (match_operand:P 0 "register_operand" "=D")
        (plus:P (match_dup 1)
-               (const_int 1)))]
+               (const_int 1)))
+   (unspec [(const_int 0)] UNSPEC_STOS)]
   "!(fixed_regs[AX_REG] || fixed_regs[DI_REG])"
   "stosb"
   [(set_attr "type" "str")
     emit_insn (gen_set_got (pic_offset_table_rtx));
   DONE;
 })
-\f
+
+(define_insn_and_split "nonlocal_goto_receiver"
+  [(unspec_volatile [(const_int 0)] UNSPECV_NLGR)]
+  "TARGET_MACHO && !TARGET_64BIT && flag_pic"
+  "#"
+  "&& reload_completed"
+  [(const_int 0)]
+{
+  if (crtl->uses_pic_offset_table)
+    {
+      rtx xops[3];
+      rtx label_rtx = gen_label_rtx ();
+      rtx tmp;
+
+      /* Get a new pic base.  */
+      emit_insn (gen_set_got_labelled (pic_offset_table_rtx, label_rtx));
+      /* Correct this with the offset from the new to the old.  */
+      xops[0] = xops[1] = pic_offset_table_rtx;
+      label_rtx = gen_rtx_LABEL_REF (SImode, label_rtx);
+      tmp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, label_rtx),
+                           UNSPEC_MACHOPIC_OFFSET);
+      xops[2] = gen_rtx_CONST (Pmode, tmp);
+      ix86_expand_binary_operator (MINUS, SImode, xops);
+    }
+  else
+    /* No pic reg restore needed.  */
+    emit_note (NOTE_INSN_DELETED);
+
+  DONE;
+})
+
 ;; Avoid redundant prefixes by splitting HImode arithmetic to SImode.
 
 (define_split
   "(TARGET_READ_MODIFY_WRITE || optimize_insn_for_size_p ())
    && peep2_reg_dead_p (4, operands[0])
    && !reg_overlap_mentioned_p (operands[0], operands[1])
+   && !reg_overlap_mentioned_p (operands[0], operands[2])
    && (<MODE>mode != QImode
        || immediate_operand (operands[2], QImode)
        || q_regs_operand (operands[2], QImode))
        || immediate_operand (operands[2], SImode)
        || q_regs_operand (operands[2], SImode))
    && !reg_overlap_mentioned_p (operands[0], operands[1])
+   && !reg_overlap_mentioned_p (operands[0], operands[2])
    && ix86_match_ccmode (peep2_next_insn (3),
                         (GET_CODE (operands[3]) == PLUS
                          || GET_CODE (operands[3]) == MINUS)