OSDN Git Service

* config/i386/i386.md (*jcc_fused_1): Handle all valid compare
[pf3gnuchains/gcc-fork.git] / gcc / config / i386 / i386.md
index 6debb18..b6b19a1 100644 (file)
        (const_int 1))
    (clobber (reg:CC FLAGS_REG))]
   "TARGET_64BIT && (TARGET_USE_BT || reload_completed)"
-  "bts{q} %1,%0"
+  "bts{q}\t{%1, %0|%0, %1}"
   [(set_attr "type" "alu1")])
 
 (define_insn "*btrq"
        (const_int 0))
    (clobber (reg:CC FLAGS_REG))]
   "TARGET_64BIT && (TARGET_USE_BT || reload_completed)"
-  "btr{q} %1,%0"
+  "btr{q}\t{%1, %0|%0, %1}"
   [(set_attr "type" "alu1")])
 
 (define_insn "*btcq"
        (not:DI (zero_extract:DI (match_dup 0) (const_int 1) (match_dup 1))))
    (clobber (reg:CC FLAGS_REG))]
   "TARGET_64BIT && (TARGET_USE_BT || reload_completed)"
-  "btc{q} %1,%0"
+  "btc{q}\t{%1, %0|%0, %1}"
   [(set_attr "type" "alu1")])
 
 ;; Allow Nocona to avoid these instructions if a register is available.
   emit_insn (gen_xordi3 (operands[0], operands[0], op1));
   DONE;
 })
+
+(define_insn "*btdi_rex64"
+  [(set (reg:CCC FLAGS_REG)
+       (compare:CCC
+         (zero_extract:DI
+           (match_operand:DI 0 "register_operand" "r")
+           (const_int 1)
+           (match_operand:DI 1 "nonmemory_operand" "rN"))
+         (const_int 0)))]
+  "TARGET_64BIT && (TARGET_USE_BT || optimize_size)"
+  "bt{q}\t{%1, %0|%0, %1}"
+  [(set_attr "type" "alu1")])
+
+(define_insn "*btsi"
+  [(set (reg:CCC FLAGS_REG)
+       (compare:CCC
+         (zero_extract:SI
+           (match_operand:SI 0 "register_operand" "r")
+           (const_int 1)
+           (match_operand:SI 1 "nonmemory_operand" "rN"))
+         (const_int 0)))]
+  "TARGET_USE_BT || optimize_size"
+  "bt{l}\t{%1, %0|%0, %1}"
+  [(set_attr "type" "alu1")])
 \f
 ;; Store-flag instructions.
 
             (const_int 2)
             (const_int 6)))])
 
+;; ??? Handle alignment requirements for compare and branch fused macro-op;
+;; the branch instruction does not start at a 16-byte boundary or cross
+;; a 16-byte boundary.
+
+(define_insn "*jcc_fused_1"
+  [(set (pc)
+       (if_then_else (match_operator 1 "comparison_operator"
+                       [(match_operand:SWI 2 "register_operand" "<r>")
+                        (match_operand:SWI 3 "const0_operand" "n")])
+        (label_ref (match_operand 0 "" ""))
+        (pc)))]
+  "TARGET_FUSE_CMP_AND_BRANCH && !TARGET_64BIT"
+{
+  return "test{<imodesuffix>}\t%2, %2\n\t"
+        "%+j%E1\t%l0\t" ASM_COMMENT_START " fused";
+}
+  [(set_attr "type" "multi")
+   (set_attr "mode" "<MODE>")])
+
+(define_insn "*jcc_fused_2"
+  [(set (pc)
+       (if_then_else (match_operator 1 "comparison_operator"
+                       [(match_operand:SWI 2 "register_operand" "<r>")
+                        (match_operand:SWI 3 "const0_operand" "n")])
+        (pc)
+        (label_ref (match_operand 0 "" ""))))]
+  "TARGET_FUSE_CMP_AND_BRANCH && !TARGET_64BIT"
+{
+  return "test{<imodesuffix>}\t%2, %2\n\t"
+        "%+j%e1\t%l0\t" ASM_COMMENT_START " fused";
+}
+  [(set_attr "type" "multi")
+   (set_attr "mode" "<MODE>")])
+
+(define_insn "*jcc_fused_3"
+  [(set (pc)
+       (if_then_else
+         (match_operator 1 "ix86_comparison_uns_operator"
+           [(match_operand:SWI 2 "nonimmediate_operand" "<r>,m,<r>")
+            (match_operand:SWI 3 "<general_operand>" "<r><i>,<r>,m")])
+        (label_ref (match_operand 0 "" ""))
+        (pc)))]
+  "TARGET_FUSE_CMP_AND_BRANCH && !TARGET_64BIT
+   && !(MEM_P (operands[2])
+       && (MEM_P (operands[3]) || CONST_INT_P (operands[3])))"
+{
+  return "cmp{<imodesuffix>}\t{%3, %2|%2, %3}\n\t"
+        "%+j%E1\t%l0\t" ASM_COMMENT_START " fused";
+}
+  [(set_attr "type" "multi")
+   (set_attr "mode" "<MODE>")])
+
+(define_insn "*jcc_fused_4"
+  [(set (pc)
+       (if_then_else
+         (match_operator 1 "ix86_comparison_uns_operator"
+           [(match_operand:SWI 2 "nonimmediate_operand" "<r>,m,<r>")
+            (match_operand:SWI 3 "<general_operand>" "<r><i>,<r>,m")])
+        (pc)
+        (label_ref (match_operand 0 "" ""))))]
+  "TARGET_FUSE_CMP_AND_BRANCH && !TARGET_64BIT
+   && !(MEM_P (operands[2])
+       && (MEM_P (operands[3]) || CONST_INT_P (operands[3])))"
+{
+  return "cmp{<imodesuffix>}\t{%3, %2|%2, %3}\n\t"
+        "%+j%e1\t%l0\t" ASM_COMMENT_START " fused";
+}
+  [(set_attr "type" "multi")
+   (set_attr "mode" "<MODE>")])
+
 ;; In general it is not safe to assume too much about CCmode registers,
 ;; so simplify-rtx stops when it sees a second one.  Under certain
 ;; conditions this is safe on x86, so help combine not create
     FAIL;
 })
 
+;; zero_extend in SImode is correct, since this is what combine pass
+;; generates from shift insn with QImode operand.  Actually, the mode of
+;; operand 2 (bit offset operand) doesn't matter since bt insn takes
+;; appropriate modulo of the bit offset value.
+
+(define_insn_and_split "*jcc_btdi_rex64"
+  [(set (pc)
+       (if_then_else (match_operator 0 "bt_comparison_operator"
+                       [(zero_extract:DI
+                          (match_operand:DI 1 "register_operand" "r")
+                          (const_int 1)
+                          (zero_extend:SI
+                            (match_operand:QI 2 "register_operand" "r")))
+                        (const_int 0)])
+                     (label_ref (match_operand 3 "" ""))
+                     (pc)))]
+  "TARGET_64BIT && (TARGET_USE_BT || optimize_size)"
+  "#"
+  "&& 1"
+  [(set (reg:CCC FLAGS_REG)
+       (compare:CCC
+         (zero_extract:DI
+           (match_dup 1)
+           (const_int 1)
+           (match_dup 2))
+         (const_int 0)))
+   (set (pc)
+       (if_then_else (match_op_dup 0 [(reg:CCC FLAGS_REG) (const_int 0)])
+                     (label_ref (match_dup 3))
+                     (pc)))]
+{
+  operands[2] = simplify_gen_subreg (DImode, operands[2], QImode, 0);
+
+  PUT_CODE (operands[0], reverse_condition (GET_CODE (operands[0])));
+})
+
+;; avoid useless masking of bit offset operand
+(define_insn_and_split "*jcc_btdi_mask_rex64"
+  [(set (pc)
+       (if_then_else (match_operator 0 "bt_comparison_operator"
+                       [(zero_extract:DI
+                          (match_operand:DI 1 "register_operand" "r")
+                          (const_int 1)
+                          (and:SI
+                            (match_operand:SI 2 "register_operand" "r")
+                            (match_operand:SI 3 "const_int_operand" "n")))])
+                     (label_ref (match_operand 4 "" ""))
+                     (pc)))]
+  "TARGET_64BIT && (TARGET_USE_BT || optimize_size)
+   && (INTVAL (operands[3]) & 0x3f) == 0x3f"
+  "#"
+  "&& 1"
+  [(set (reg:CCC FLAGS_REG)
+       (compare:CCC
+         (zero_extract:DI
+           (match_dup 1)
+           (const_int 1)
+           (match_dup 2))
+         (const_int 0)))
+   (set (pc)
+       (if_then_else (match_op_dup 0 [(reg:CCC FLAGS_REG) (const_int 0)])
+                     (label_ref (match_dup 4))
+                     (pc)))]
+{
+  operands[2] = simplify_gen_subreg (DImode, operands[2], SImode, 0);
+
+  PUT_CODE (operands[0], reverse_condition (GET_CODE (operands[0])));
+})
+
+(define_insn_and_split "*jcc_btsi"
+  [(set (pc)
+       (if_then_else (match_operator 0 "bt_comparison_operator"
+                       [(zero_extract:SI
+                          (match_operand:SI 1 "register_operand" "r")
+                          (const_int 1)
+                          (zero_extend:SI
+                            (match_operand:QI 2 "register_operand" "r")))
+                        (const_int 0)])
+                     (label_ref (match_operand 3 "" ""))
+                     (pc)))]
+  "TARGET_USE_BT || optimize_size"
+  "#"
+  "&& 1"
+  [(set (reg:CCC FLAGS_REG)
+       (compare:CCC
+         (zero_extract:SI
+           (match_dup 1)
+           (const_int 1)
+           (match_dup 2))
+         (const_int 0)))
+   (set (pc)
+       (if_then_else (match_op_dup 0 [(reg:CCC FLAGS_REG) (const_int 0)])
+                     (label_ref (match_dup 3))
+                     (pc)))]
+{
+  operands[2] = simplify_gen_subreg (SImode, operands[2], QImode, 0);
+
+  PUT_CODE (operands[0], reverse_condition (GET_CODE (operands[0])));
+})
+
+;; avoid useless masking of bit offset operand
+(define_insn_and_split "*jcc_btsi_mask"
+  [(set (pc)
+       (if_then_else (match_operator 0 "bt_comparison_operator"
+                       [(zero_extract:SI
+                          (match_operand:SI 1 "register_operand" "r")
+                          (const_int 1)
+                          (and:SI
+                            (match_operand:SI 2 "register_operand" "r")
+                            (match_operand:SI 3 "const_int_operand" "n")))])
+                     (label_ref (match_operand 4 "" ""))
+                     (pc)))]
+  "(TARGET_USE_BT || optimize_size)
+   && (INTVAL (operands[3]) & 0x1f) == 0x1f"
+  "#"
+  "&& 1"
+  [(set (reg:CCC FLAGS_REG)
+       (compare:CCC
+         (zero_extract:SI
+           (match_dup 1)
+           (const_int 1)
+           (match_dup 2))
+         (const_int 0)))
+   (set (pc)
+       (if_then_else (match_op_dup 0 [(reg:CCC FLAGS_REG) (const_int 0)])
+                     (label_ref (match_dup 4))
+                     (pc)))]
+  "PUT_CODE (operands[0], reverse_condition (GET_CODE (operands[0])));")
+
+(define_insn_and_split "*jcc_btsi_1"
+  [(set (pc)
+       (if_then_else (match_operator 0 "bt_comparison_operator"
+                       [(and:SI
+                          (lshiftrt:SI
+                            (match_operand:SI 1 "register_operand" "r")
+                            (match_operand:QI 2 "register_operand" "r"))
+                          (const_int 1))
+                        (const_int 0)])
+                     (label_ref (match_operand 3 "" ""))
+                     (pc)))]
+  "TARGET_USE_BT || optimize_size"
+  "#"
+  "&& 1"
+  [(set (reg:CCC FLAGS_REG)
+       (compare:CCC
+         (zero_extract:SI
+           (match_dup 1)
+           (const_int 1)
+           (match_dup 2))
+         (const_int 0)))
+   (set (pc)
+       (if_then_else (match_op_dup 0 [(reg:CCC FLAGS_REG) (const_int 0)])
+                     (label_ref (match_dup 3))
+                     (pc)))]
+{
+  operands[2] = simplify_gen_subreg (SImode, operands[2], QImode, 0);
+
+  PUT_CODE (operands[0], reverse_condition (GET_CODE (operands[0])));
+})
+
+;; avoid useless masking of bit offset operand
+(define_insn_and_split "*jcc_btsi_mask_1"
+  [(set (pc)
+       (if_then_else
+         (match_operator 0 "bt_comparison_operator"
+           [(and:SI
+              (lshiftrt:SI
+                (match_operand:SI 1 "register_operand" "r")
+                (subreg:QI
+                  (and:SI
+                    (match_operand:SI 2 "register_operand" "r")
+                    (match_operand:SI 3 "const_int_operand" "n")) 0))
+              (const_int 1))
+            (const_int 0)])
+         (label_ref (match_operand 4 "" ""))
+         (pc)))]
+  "(TARGET_USE_BT || optimize_size)
+   && (INTVAL (operands[3]) & 0x1f) == 0x1f"
+  "#"
+  "&& 1"
+  [(set (reg:CCC FLAGS_REG)
+       (compare:CCC
+         (zero_extract:SI
+           (match_dup 1)
+           (const_int 1)
+           (match_dup 2))
+         (const_int 0)))
+   (set (pc)
+       (if_then_else (match_op_dup 0 [(reg:CCC FLAGS_REG) (const_int 0)])
+                     (label_ref (match_dup 4))
+                     (pc)))]
+  "PUT_CODE (operands[0], reverse_condition (GET_CODE (operands[0])));")
+
 ;; Define combination compare-and-branch fp compare instructions to use
 ;; during early optimization.  Splitting the operation apart early makes
 ;; for bad code when we want to reverse the operation.