And this is the i?86 specific part of -fsanitize=signed-integer-overflow, split out of the huge patch. It really is dependent on the generic parts, when commiting, I'll put both parts together.
Uros, would you mind taking a look at this? Regtested/bootstrapped on x86_64-linux. Ok for trunk? 2013-12-04 Jakub Jelinek <ja...@redhat.com> Marek Polacek <pola...@redhat.com> * config/i386/i386.md (addv<mode>4, subv<mode>4, mulv<mode>4, negv<mode>3, negv<mode>3_1): Define expands. (*addv<mode>4, *subv<mode>4, *mulv<mode>4, *negv<mode>3): Define insns. --- gcc/config/i386/i386.md.mp 2013-12-04 12:15:33.508905947 +0100 +++ gcc/config/i386/i386.md 2013-12-04 12:15:39.608929341 +0100 @@ -6153,6 +6153,42 @@ [(set_attr "type" "alu") (set_attr "mode" "QI")]) +(define_mode_attr widerintmode [(QI "HI") (HI "SI") (SI "DI") (DI "TI")]) + +;; Add with jump on overflow. +(define_expand "addv<mode>4" + [(parallel [(set (reg:CCO FLAGS_REG) + (eq:CCO (plus:<widerintmode> + (sign_extend:<widerintmode> + (match_operand:SWI 1 "register_operand")) + (sign_extend:<widerintmode> + (match_operand:SWI 2 "<general_operand>"))) + (sign_extend:<widerintmode> + (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)))] + "") + +(define_insn "*addv<mode>4" + [(set (reg:CCO FLAGS_REG) + (eq:CCO (plus:<widerintmode> + (sign_extend:<widerintmode> + (match_operand:SWI 1 "nonimmediate_operand" "%0,0")) + (sign_extend:<widerintmode> + (match_operand:SWI 2 "<general_operand>" "<g>,<r><i>"))) + (sign_extend:<widerintmode> + (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. @@ -6390,6 +6426,40 @@ [(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:<widerintmode> + (sign_extend:<widerintmode> + (match_operand:SWI 1 "register_operand")) + (sign_extend:<widerintmode> + (match_operand:SWI 2 "<general_operand>"))) + (sign_extend:<widerintmode> + (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)))] + "") + +(define_insn "*subv<mode>4" + [(set (reg:CCO FLAGS_REG) + (eq:CCO (minus:<widerintmode> + (sign_extend:<widerintmode> + (match_operand:SWI 1 "nonimmediate_operand" "0,0")) + (sign_extend:<widerintmode> + (match_operand:SWI 2 "<general_operand>" "<r><i>,<r>m"))) + (sign_extend:<widerintmode> + (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") @@ -6704,6 +6774,59 @@ (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:<widerintmode> + (sign_extend:<widerintmode> + (match_operand:SWI48 1 "register_operand")) + (sign_extend:<widerintmode> + (match_operand:SWI48 2 "<general_operand>"))) + (sign_extend:<widerintmode> + (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:<widerintmode> + (sign_extend:<widerintmode> + (match_operand:SWI 1 "nonimmediate_operand" "%rm,rm,0")) + (sign_extend:<widerintmode> + (match_operand:SWI 2 "<general_operand>" "K,<i>,mr"))) + (sign_extend:<widerintmode> + (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> @@ -8617,6 +8740,49 @@ [(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") + (const_int 0))) + (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)))] + "" +{ + rtx minv = GEN_INT (HOST_WIDE_INT_M1U + << (GET_MODE_BITSIZE (<MODE>mode) - 1)); + emit_insn (gen_negv<mode>3_1 (operands[0], operands[1], minv, operands[2])); + DONE; +}) + +(define_expand "negv<mode>3_1" + [(parallel [(set (reg:CCO FLAGS_REG) + (ne:CCO (match_operand:SWI 1 "nonimmediate_operand") + (match_operand:SWI 2 "const_int_operand"))) + (set (match_operand:SWI 0 "nonimmediate_operand") + (neg:SWI (match_dup 1)))]) + (set (pc) (if_then_else + (eq (reg:CCO FLAGS_REG) (const_int 0)) + (label_ref (match_operand 3)) + (pc)))] + "") + +(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" Marek