Implement -fsanitize=signed-integer-overflow.
[gcc.git] / gcc / config / i386 / i386.md
index 0c732c7689f62993faf9fe2fa9c433ba5a9d5302..5ff66ccf1e59e25a7765558cdc217ec5c9f5065c 100644 (file)
                           (TI "TARGET_64BIT")])
 
 ;; Double word integer modes as mode attribute.
-(define_mode_attr DWI [(SI "DI") (DI "TI")])
-(define_mode_attr dwi [(SI "di") (DI "ti")])
+(define_mode_attr DWI [(QI "HI") (HI "SI") (SI "DI") (DI "TI")])
+(define_mode_attr dwi [(QI "hi") (HI "si") (SI "di") (DI "ti")])
 
 ;; Half mode for double word integer modes.
 (define_mode_iterator DWIH [(SI "!TARGET_64BIT")
   [(set_attr "type" "alu")
    (set_attr "mode" "QI")])
 
+;; Add with jump on overflow.
+(define_expand "addv<mode>4"
+  [(parallel [(set (reg:CCO FLAGS_REG)
+                  (eq:CCO (plus:<DWI>
+                             (sign_extend:<DWI>
+                                (match_operand:SWI 1 "nonimmediate_operand"))
+                             (sign_extend:<DWI>
+                                (match_operand:SWI 2 "<general_operand>")))
+                          (sign_extend:<DWI>
+                             (plus:SWI (match_dup 1) (match_dup 2)))))
+             (set (match_operand:SWI 0 "register_operand")
+                  (plus:SWI (match_dup 1) (match_dup 2)))])
+   (set (pc) (if_then_else
+              (eq (reg:CCO FLAGS_REG) (const_int 0))
+              (label_ref (match_operand 3))
+              (pc)))]
+  ""
+  "ix86_fixup_binary_operands_no_copy (PLUS, <MODE>mode, operands);")
+
+(define_insn "*addv<mode>4"
+  [(set (reg:CCO FLAGS_REG)
+       (eq:CCO (plus:<DWI>
+                  (sign_extend:<DWI>
+                     (match_operand:SWI 1 "nonimmediate_operand" "%0,0"))
+                  (sign_extend:<DWI>
+                     (match_operand:SWI 2 "<general_operand>" "<g>,<r><i>")))
+               (sign_extend:<DWI>
+                  (plus:SWI (match_dup 1) (match_dup 2)))))
+   (set (match_operand:SWI 0 "nonimmediate_operand" "=<r>,<r>m")
+       (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>")])
+
 ;; The lea patterns for modes less than 32 bits need to be matched by
 ;; several insns converted to real lea by splitters.
 
   [(set_attr "type" "alu")
    (set_attr "mode" "SI")])
 
+;; Subtract with jump on overflow.
+(define_expand "subv<mode>4"
+  [(parallel [(set (reg:CCO FLAGS_REG)
+                  (eq:CCO (minus:<DWI>
+                             (sign_extend:<DWI>
+                                (match_operand:SWI 1 "nonimmediate_operand"))
+                             (sign_extend:<DWI>
+                                (match_operand:SWI 2 "<general_operand>")))
+                          (sign_extend:<DWI>
+                             (minus:SWI (match_dup 1) (match_dup 2)))))
+             (set (match_operand:SWI 0 "register_operand")
+                  (minus:SWI (match_dup 1) (match_dup 2)))])
+   (set (pc) (if_then_else
+              (eq (reg:CCO FLAGS_REG) (const_int 0))
+              (label_ref (match_operand 3))
+              (pc)))]
+  ""
+  "ix86_fixup_binary_operands_no_copy (MINUS, <MODE>mode, operands);")
+
+(define_insn "*subv<mode>4"
+  [(set (reg:CCO FLAGS_REG)
+       (eq:CCO (minus:<DWI>
+                  (sign_extend:<DWI>
+                     (match_operand:SWI 1 "nonimmediate_operand" "0,0"))
+                  (sign_extend:<DWI>
+                     (match_operand:SWI 2 "<general_operand>" "<r><i>,<r>m")))
+               (sign_extend:<DWI>
+                  (minus:SWI (match_dup 1) (match_dup 2)))))
+   (set (match_operand:SWI 0 "nonimmediate_operand" "=<r>m,<r>")
+       (minus:SWI (match_dup 1) (match_dup 2)))]
+  "ix86_binary_operator_ok (MINUS, <MODE>mode, operands)"
+  "sub{<imodesuffix>}\t{%2, %0|%0, %2}"
+  [(set_attr "type" "alu")
+   (set_attr "mode" "<MODE>")])
+
 (define_insn "*sub<mode>_3"
   [(set (reg FLAGS_REG)
        (compare (match_operand:SWI 1 "nonimmediate_operand" "0,0")
    (set_attr "bdver1_decode" "direct")
    (set_attr "mode" "QI")])
 
+;; Multiply with jump on overflow.
+(define_expand "mulv<mode>4"
+  [(parallel [(set (reg:CCO FLAGS_REG)
+                  (eq:CCO (mult:<DWI>
+                             (sign_extend:<DWI>
+                                (match_operand:SWI48 1 "register_operand"))
+                             (sign_extend:<DWI>
+                                (match_operand:SWI48 2 "<general_operand>")))
+                          (sign_extend:<DWI>
+                             (mult:SWI48 (match_dup 1) (match_dup 2)))))
+             (set (match_operand:SWI48 0 "register_operand")
+                  (mult:SWI48 (match_dup 1) (match_dup 2)))])
+   (set (pc) (if_then_else
+              (eq (reg:CCO FLAGS_REG) (const_int 0))
+              (label_ref (match_operand 3))
+              (pc)))])
+
+(define_insn "*mulv<mode>4"
+  [(set (reg:CCO FLAGS_REG)
+       (eq:CCO (mult:<DWI>
+                  (sign_extend:<DWI>
+                     (match_operand:SWI 1 "nonimmediate_operand" "%rm,rm,0"))
+                  (sign_extend:<DWI>
+                     (match_operand:SWI 2 "<general_operand>" "K,<i>,mr")))
+               (sign_extend:<DWI>
+                  (mult:SWI (match_dup 1) (match_dup 2)))))
+   (set (match_operand:SWI 0 "register_operand" "=r,r,r")
+       (mult:SWI (match_dup 1) (match_dup 2)))]
+  "!(MEM_P (operands[1]) && MEM_P (operands[2]))"
+  "@
+   imul{<imodesuffix>}\t{%2, %1, %0|%0, %1, %2}
+   imul{<imodesuffix>}\t{%2, %1, %0|%0, %1, %2}
+   imul{<imodesuffix>}\t{%2, %0|%0, %2}"
+  [(set_attr "type" "imul")
+   (set_attr "prefix_0f" "0,0,1")
+   (set (attr "athlon_decode")
+       (cond [(eq_attr "cpu" "athlon")
+                 (const_string "vector")
+              (eq_attr "alternative" "1")
+                 (const_string "vector")
+              (and (eq_attr "alternative" "2")
+                   (match_operand 1 "memory_operand"))
+                 (const_string "vector")]
+             (const_string "direct")))
+   (set (attr "amdfam10_decode")
+       (cond [(and (eq_attr "alternative" "0,1")
+                   (match_operand 1 "memory_operand"))
+                 (const_string "vector")]
+             (const_string "direct")))
+   (set_attr "bdver1_decode" "direct")
+   (set_attr "mode" "<MODE>")])
+
 (define_expand "<u>mul<mode><dwi>3"
   [(parallel [(set (match_operand:<DWI> 0 "register_operand")
                   (mult:<DWI>
   [(set_attr "type" "negnot")
    (set_attr "mode" "SI")])
 
+;; Negate with jump on overflow.
+(define_expand "negv<mode>3"
+  [(parallel [(set (reg:CCO FLAGS_REG)
+                  (ne:CCO (match_operand:SWI 1 "register_operand")
+                          (match_dup 3)))
+             (set (match_operand:SWI 0 "register_operand")
+                  (neg:SWI (match_dup 1)))])
+   (set (pc) (if_then_else
+              (eq (reg:CCO FLAGS_REG) (const_int 0))
+              (label_ref (match_operand 2))
+              (pc)))]
+  ""
+{
+  operands[3]
+    = gen_int_mode (HOST_WIDE_INT_1U << (GET_MODE_BITSIZE (<MODE>mode) - 1),
+                   <MODE>mode);
+})
+
+(define_insn "*negv<mode>3"
+  [(set (reg:CCO FLAGS_REG)
+       (ne:CCO (match_operand:SWI 1 "nonimmediate_operand" "0")
+               (match_operand:SWI 2 "const_int_operand")))
+   (set (match_operand:SWI 0 "nonimmediate_operand" "=<r>m")
+       (neg:SWI (match_dup 1)))]
+  "ix86_unary_operator_ok (NEG, <MODE>mode, operands)
+   && mode_signbit_p (<MODE>mode, operands[2])"
+  "neg{<imodesuffix>}\t%0"
+  [(set_attr "type" "negnot")
+   (set_attr "mode" "<MODE>")])
+
 ;; Changing of sign for FP values is doable using integer unit too.
 
 (define_expand "<code><mode>2"