On Wed, Dec 04, 2013 at 08:23:22PM +0100, Uros Bizjak wrote: > > My memory is fuzzy about that, but I think that was my first version which > > didn't work, because with match_dup then it requires on the internal-fn.c > > side to pass 4 arguments instead of just 3. I can try again though.
Weird, now it works, dunno what I have done differently before. Though, I've discovered a bug in internal-fn.c for the negation case. So is this everything you wanted? 2013-12-04 Jakub Jelinek <ja...@redhat.com> Marek Polacek <pola...@redhat.com> * config/i386/i386.md (DWI, dwi): Add QImode and HImode cases. (addv<mode>4, subv<mode>4, mulv<mode>4, negv<mode>3): New expanders. (*addv<mode>4, *subv<mode>4, *mulv<mode>4, *negv<mode>3): New insns. * internal-fn.c (ubsan_expand_si_overflow_neg_check): The return value lives in res rather than target. --- gcc/config/i386/i386.md.jj 2013-12-04 12:05:46.689185140 +0100 +++ gcc/config/i386/i386.md 2013-12-04 20:40:25.417309596 +0100 @@ -905,8 +905,8 @@ (define_mode_iterator DWI [(DI "!TARGET_ (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") @@ -6160,6 +6160,41 @@ (define_insn "*addqi_ext_2" [(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. @@ -6397,6 +6432,41 @@ (define_insn "*subsi_2_zext" [(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") @@ -6711,6 +6781,58 @@ (define_insn "*mulqi3_1" (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> @@ -8624,6 +8746,36 @@ (define_insn "*negsi2_cmpz_zext" [(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" --- gcc/internal-fn.c.jj 2013-12-04 20:09:39.000000000 +0100 +++ gcc/internal-fn.c 2013-12-04 20:54:40.994939539 +0100 @@ -291,7 +291,6 @@ ubsan_expand_si_overflow_neg_check (gimp && !find_reg_note (last, REG_BR_PROB, 0)) add_int_reg_note (last, REG_BR_PROB, PROB_VERY_UNLIKELY); emit_jump (done_label); - res = target; } else { Jakub