gcc/ 2010-07-01 H.J. Lu PR rtl-optimization/44695 * config/i386/i386.md (extract_code): Removed. (divmodqi4): Likewise. (divmodqi4): New. (udivmodqi4): Likewise. (divmodhiqi3): Change div/mod to HImode and extend operand 2 to HImode. (udivmodhiqi3): Likewise. gcc/testsuite/ 2010-07-01 H.J. Lu PR rtl-optimization/44695 * gcc.dg/torture/pr44695.c: New. diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 1714d50..de1d8f5 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -760,8 +760,6 @@ ;; Used in signed and unsigned divisions. (define_code_iterator any_div [div udiv]) -(define_code_attr extract_code - [(div "SIGN_EXTRACT") (udiv "ZERO_EXTRACT")]) ;; Instruction prefix for signed and unsigned operations. (define_code_attr sgnprefix [(sign_extend "i") (zero_extend "") @@ -7308,9 +7306,9 @@ ;; Divmod instructions. -(define_expand "divmodqi4" +(define_expand "divmodqi4" [(parallel [(set (match_operand:QI 0 "register_operand" "") - (any_div:QI + (div:QI (match_operand:QI 1 "register_operand" "") (match_operand:QI 2 "nonimmediate_operand" ""))) (set (match_operand:QI 3 "register_operand" "") @@ -7326,31 +7324,51 @@ /* Extend operands[1] to HImode. Generate 8bit divide. Result is in AX. */ - if ( == SIGN_EXTRACT) - { - emit_insn (gen_extendqihi2 (tmp1, operands[1])); - emit_insn (gen_divmodhiqi3 (tmp0, tmp1, operands[2])); + emit_insn (gen_extendqihi2 (tmp1, operands[1])); + emit_insn (gen_divmodhiqi3 (tmp0, tmp1, operands[2])); - div = gen_rtx_DIV (QImode, operands[1], operands[2]); - mod = gen_rtx_MOD (QImode, operands[1], operands[2]); + div = gen_rtx_DIV (QImode, operands[1], operands[2]); + mod = gen_rtx_MOD (QImode, operands[1], operands[2]); - tmp1 = gen_rtx_ (QImode, tmp0, - GEN_INT (8), GEN_INT (8)); - } - else - { - emit_insn (gen_zero_extendqihi2 (tmp1, operands[1])); - emit_insn (gen_udivmodhiqi3 (tmp0, tmp1, operands[2])); + /* Extract remainder from AH. */ + tmp1 = gen_rtx_SIGN_EXTRACT (QImode, tmp0, GEN_INT (8), GEN_INT (8)); + insn = emit_move_insn (operands[3], tmp1); + set_unique_reg_note (insn, REG_EQUAL, mod); - div = gen_rtx_UDIV (QImode, operands[1], operands[2]); - mod = gen_rtx_UMOD (QImode, operands[1], operands[2]); + /* Extract quotient from AL. */ + insn = emit_move_insn (operands[0], gen_lowpart (QImode, tmp0)); + set_unique_reg_note (insn, REG_EQUAL, div); - tmp1 = gen_rtx_ (SImode, tmp0, - GEN_INT (8), GEN_INT (8)); - tmp1 = simplify_gen_subreg (QImode, tmp1, SImode, 0); - } + DONE; +}) + +(define_expand "udivmodqi4" + [(parallel [(set (match_operand:QI 0 "register_operand" "") + (udiv:QI + (match_operand:QI 1 "register_operand" "") + (match_operand:QI 2 "nonimmediate_operand" ""))) + (set (match_operand:QI 3 "register_operand" "") + (umod:QI (match_dup 1) (match_dup 2))) + (clobber (reg:CC FLAGS_REG))])] + "TARGET_QIMODE_MATH" +{ + rtx div, mod, insn; + rtx tmp0, tmp1; + + tmp0 = gen_reg_rtx (HImode); + tmp1 = gen_reg_rtx (HImode); + + /* Extend operands[1] to HImode. Generate 8bit divide. Result is + in AX. */ + emit_insn (gen_zero_extendqihi2 (tmp1, operands[1])); + emit_insn (gen_udivmodhiqi3 (tmp0, tmp1, operands[2])); + + div = gen_rtx_UDIV (QImode, operands[1], operands[2]); + mod = gen_rtx_UMOD (QImode, operands[1], operands[2]); /* Extract remainder from AH. */ + tmp1 = gen_rtx_ZERO_EXTRACT (SImode, tmp0, GEN_INT (8), GEN_INT (8)); + tmp1 = simplify_gen_subreg (QImode, tmp1, SImode, 0); insn = emit_move_insn (operands[3], tmp1); set_unique_reg_note (insn, REG_EQUAL, mod); @@ -7364,15 +7382,22 @@ ;; Divide AX by r/m8, with result stored in ;; AL <- Quotient ;; AH <- Remainder +;; Change div/mod to HImode and extend the second argument to HImode +;; so that mode of div/mod matches with mode of arguments. Otherwise +;; combine may fail. (define_insn "divmodhiqi3" [(set (match_operand:HI 0 "register_operand" "=a") (ior:HI (ashift:HI (zero_extend:HI - (mod:QI (match_operand:HI 1 "register_operand" "0") - (match_operand:QI 2 "nonimmediate_operand" "qm"))) + (truncate:QI + (mod:HI (match_operand:HI 1 "register_operand" "0") + (sign_extend:HI + (match_operand:QI 2 "nonimmediate_operand" "qm"))))) (const_int 8)) - (zero_extend:HI (div:QI (match_dup 1) (match_dup 2))))) + (zero_extend:HI + (truncate:QI + (div:HI (match_dup 1) (sign_extend:HI (match_dup 2))))))) (clobber (reg:CC FLAGS_REG))] "TARGET_QIMODE_MATH" "idiv{b}\t%2" @@ -7384,10 +7409,14 @@ (ior:HI (ashift:HI (zero_extend:HI - (umod:QI (match_operand:HI 1 "register_operand" "0") - (match_operand:QI 2 "nonimmediate_operand" "qm"))) + (truncate:QI + (mod:HI (match_operand:HI 1 "register_operand" "0") + (zero_extend:HI + (match_operand:QI 2 "nonimmediate_operand" "qm"))))) (const_int 8)) - (zero_extend:HI (udiv:QI (match_dup 1) (match_dup 2))))) + (zero_extend:HI + (truncate:QI + (div:HI (match_dup 1) (zero_extend:HI (match_dup 2))))))) (clobber (reg:CC FLAGS_REG))] "TARGET_QIMODE_MATH" "div{b}\t%2" --- /dev/null 2010-06-16 10:11:06.602750711 -0700 +++ gcc/gcc/testsuite/gcc.dg/torture/pr44695.c 2010-06-29 11:49:12.186942482 -0700 @@ -0,0 +1,15 @@ +/* { dg-do compile } */ + +typedef unsigned char uint8_t; + +static uint8_t +safe_div_func_uint8_t_u_u (uint8_t ui1, uint8_t ui2) +{ + return ui2 ? ui2 : (ui1 / ui2); +} + +int +int81 (int x) +{ + return safe_div_func_uint8_t_u_u (1, 8 & x); +}