mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-21 00:21:03 +08:00
* config/i386/i386.md: Rearrange divmod patterns a bit.
From-SVN: r164347
This commit is contained in:
parent
26ec93086a
commit
b3df2256e7
@ -7154,125 +7154,6 @@
|
||||
|
||||
;; Divmod instructions.
|
||||
|
||||
(define_expand "divmodqi4"
|
||||
[(parallel [(set (match_operand:QI 0 "register_operand" "")
|
||||
(div:QI
|
||||
(match_operand:QI 1 "register_operand" "")
|
||||
(match_operand:QI 2 "nonimmediate_operand" "")))
|
||||
(set (match_operand:QI 3 "register_operand" "")
|
||||
(mod: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_extendqihi2 (tmp1, operands[1]));
|
||||
emit_insn (gen_divmodhiqi3 (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);
|
||||
|
||||
mod = gen_rtx_MOD (QImode, operands[1], operands[2]);
|
||||
set_unique_reg_note (insn, REG_EQUAL, mod);
|
||||
|
||||
/* Extract quotient from AL. */
|
||||
insn = emit_move_insn (operands[0], gen_lowpart (QImode, tmp0));
|
||||
|
||||
div = gen_rtx_DIV (QImode, operands[1], operands[2]);
|
||||
set_unique_reg_note (insn, REG_EQUAL, div);
|
||||
|
||||
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]));
|
||||
|
||||
/* 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);
|
||||
|
||||
mod = gen_rtx_UMOD (QImode, operands[1], operands[2]);
|
||||
set_unique_reg_note (insn, REG_EQUAL, mod);
|
||||
|
||||
/* Extract quotient from AL. */
|
||||
insn = emit_move_insn (operands[0], gen_lowpart (QImode, tmp0));
|
||||
|
||||
div = gen_rtx_UDIV (QImode, operands[1], operands[2]);
|
||||
set_unique_reg_note (insn, REG_EQUAL, div);
|
||||
|
||||
DONE;
|
||||
})
|
||||
|
||||
;; 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
|
||||
(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
|
||||
(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"
|
||||
[(set_attr "type" "idiv")
|
||||
(set_attr "mode" "QI")])
|
||||
|
||||
(define_insn "udivmodhiqi3"
|
||||
[(set (match_operand:HI 0 "register_operand" "=a")
|
||||
(ior:HI
|
||||
(ashift:HI
|
||||
(zero_extend:HI
|
||||
(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
|
||||
(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"
|
||||
[(set_attr "type" "idiv")
|
||||
(set_attr "mode" "QI")])
|
||||
|
||||
(define_expand "divmod<mode>4"
|
||||
[(parallel [(set (match_operand:SWIM248 0 "register_operand" "")
|
||||
(div:SWIM248
|
||||
@ -7282,41 +7163,6 @@
|
||||
(mod:SWIM248 (match_dup 1) (match_dup 2)))
|
||||
(clobber (reg:CC FLAGS_REG))])])
|
||||
|
||||
(define_insn_and_split "*divmod<mode>4"
|
||||
[(set (match_operand:SWIM248 0 "register_operand" "=a")
|
||||
(div:SWIM248 (match_operand:SWIM248 2 "register_operand" "0")
|
||||
(match_operand:SWIM248 3 "nonimmediate_operand" "rm")))
|
||||
(set (match_operand:SWIM248 1 "register_operand" "=&d")
|
||||
(mod:SWIM248 (match_dup 2) (match_dup 3)))
|
||||
(clobber (reg:CC FLAGS_REG))]
|
||||
""
|
||||
"#"
|
||||
"reload_completed"
|
||||
[(parallel [(set (match_dup 1)
|
||||
(ashiftrt:SWIM248 (match_dup 4) (match_dup 5)))
|
||||
(clobber (reg:CC FLAGS_REG))])
|
||||
(parallel [(set (match_dup 0)
|
||||
(div:SWIM248 (match_dup 2) (match_dup 3)))
|
||||
(set (match_dup 1)
|
||||
(mod:SWIM248 (match_dup 2) (match_dup 3)))
|
||||
(use (match_dup 1))
|
||||
(clobber (reg:CC FLAGS_REG))])]
|
||||
{
|
||||
operands[5] = GEN_INT (GET_MODE_BITSIZE (<MODE>mode)-1);
|
||||
|
||||
if (<MODE>mode != HImode
|
||||
&& (optimize_function_for_size_p (cfun) || TARGET_USE_CLTD))
|
||||
operands[4] = operands[2];
|
||||
else
|
||||
{
|
||||
/* Avoid use of cltd in favor of a mov+shift. */
|
||||
emit_move_insn (operands[1], operands[2]);
|
||||
operands[4] = operands[1];
|
||||
}
|
||||
}
|
||||
[(set_attr "type" "multi")
|
||||
(set_attr "mode" "<MODE>")])
|
||||
|
||||
;; Split with 8bit unsigned divide:
|
||||
;; if (dividend an divisor are in [0-255])
|
||||
;; use 8bit unsigned integer divide
|
||||
@ -7371,6 +7217,41 @@
|
||||
[(set_attr "type" "multi")
|
||||
(set_attr "mode" "<MODE>")])
|
||||
|
||||
(define_insn_and_split "*divmod<mode>4"
|
||||
[(set (match_operand:SWIM248 0 "register_operand" "=a")
|
||||
(div:SWIM248 (match_operand:SWIM248 2 "register_operand" "0")
|
||||
(match_operand:SWIM248 3 "nonimmediate_operand" "rm")))
|
||||
(set (match_operand:SWIM248 1 "register_operand" "=&d")
|
||||
(mod:SWIM248 (match_dup 2) (match_dup 3)))
|
||||
(clobber (reg:CC FLAGS_REG))]
|
||||
""
|
||||
"#"
|
||||
"reload_completed"
|
||||
[(parallel [(set (match_dup 1)
|
||||
(ashiftrt:SWIM248 (match_dup 4) (match_dup 5)))
|
||||
(clobber (reg:CC FLAGS_REG))])
|
||||
(parallel [(set (match_dup 0)
|
||||
(div:SWIM248 (match_dup 2) (match_dup 3)))
|
||||
(set (match_dup 1)
|
||||
(mod:SWIM248 (match_dup 2) (match_dup 3)))
|
||||
(use (match_dup 1))
|
||||
(clobber (reg:CC FLAGS_REG))])]
|
||||
{
|
||||
operands[5] = GEN_INT (GET_MODE_BITSIZE (<MODE>mode)-1);
|
||||
|
||||
if (<MODE>mode != HImode
|
||||
&& (optimize_function_for_size_p (cfun) || TARGET_USE_CLTD))
|
||||
operands[4] = operands[2];
|
||||
else
|
||||
{
|
||||
/* Avoid use of cltd in favor of a mov+shift. */
|
||||
emit_move_insn (operands[1], operands[2]);
|
||||
operands[4] = operands[1];
|
||||
}
|
||||
}
|
||||
[(set_attr "type" "multi")
|
||||
(set_attr "mode" "<MODE>")])
|
||||
|
||||
(define_insn "*divmod<mode>4_noext"
|
||||
[(set (match_operand:SWIM248 0 "register_operand" "=a")
|
||||
(div:SWIM248 (match_operand:SWIM248 2 "register_operand" "0")
|
||||
@ -7384,6 +7265,68 @@
|
||||
[(set_attr "type" "idiv")
|
||||
(set_attr "mode" "<MODE>")])
|
||||
|
||||
(define_expand "divmodqi4"
|
||||
[(parallel [(set (match_operand:QI 0 "register_operand" "")
|
||||
(div:QI
|
||||
(match_operand:QI 1 "register_operand" "")
|
||||
(match_operand:QI 2 "nonimmediate_operand" "")))
|
||||
(set (match_operand:QI 3 "register_operand" "")
|
||||
(mod: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_extendqihi2 (tmp1, operands[1]));
|
||||
emit_insn (gen_divmodhiqi3 (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);
|
||||
|
||||
mod = gen_rtx_MOD (QImode, operands[1], operands[2]);
|
||||
set_unique_reg_note (insn, REG_EQUAL, mod);
|
||||
|
||||
/* Extract quotient from AL. */
|
||||
insn = emit_move_insn (operands[0], gen_lowpart (QImode, tmp0));
|
||||
|
||||
div = gen_rtx_DIV (QImode, operands[1], operands[2]);
|
||||
set_unique_reg_note (insn, REG_EQUAL, div);
|
||||
|
||||
DONE;
|
||||
})
|
||||
|
||||
;; 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
|
||||
(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
|
||||
(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"
|
||||
[(set_attr "type" "idiv")
|
||||
(set_attr "mode" "QI")])
|
||||
|
||||
(define_expand "udivmod<mode>4"
|
||||
[(parallel [(set (match_operand:SWIM248 0 "register_operand" "")
|
||||
(udiv:SWIM248
|
||||
@ -7393,27 +7336,6 @@
|
||||
(umod:SWIM248 (match_dup 1) (match_dup 2)))
|
||||
(clobber (reg:CC FLAGS_REG))])])
|
||||
|
||||
(define_insn_and_split "*udivmod<mode>4"
|
||||
[(set (match_operand:SWIM248 0 "register_operand" "=a")
|
||||
(udiv:SWIM248 (match_operand:SWIM248 2 "register_operand" "0")
|
||||
(match_operand:SWIM248 3 "nonimmediate_operand" "rm")))
|
||||
(set (match_operand:SWIM248 1 "register_operand" "=&d")
|
||||
(umod:SWIM248 (match_dup 2) (match_dup 3)))
|
||||
(clobber (reg:CC FLAGS_REG))]
|
||||
""
|
||||
"#"
|
||||
"reload_completed"
|
||||
[(set (match_dup 1) (const_int 0))
|
||||
(parallel [(set (match_dup 0)
|
||||
(udiv:SWIM248 (match_dup 2) (match_dup 3)))
|
||||
(set (match_dup 1)
|
||||
(umod:SWIM248 (match_dup 2) (match_dup 3)))
|
||||
(use (match_dup 1))
|
||||
(clobber (reg:CC FLAGS_REG))])]
|
||||
""
|
||||
[(set_attr "type" "multi")
|
||||
(set_attr "mode" "<MODE>")])
|
||||
|
||||
;; Split with 8bit unsigned divide:
|
||||
;; if (dividend an divisor are in [0-255])
|
||||
;; use 8bit unsigned integer divide
|
||||
@ -7455,6 +7377,27 @@
|
||||
[(set_attr "type" "multi")
|
||||
(set_attr "mode" "<MODE>")])
|
||||
|
||||
(define_insn_and_split "*udivmod<mode>4"
|
||||
[(set (match_operand:SWIM248 0 "register_operand" "=a")
|
||||
(udiv:SWIM248 (match_operand:SWIM248 2 "register_operand" "0")
|
||||
(match_operand:SWIM248 3 "nonimmediate_operand" "rm")))
|
||||
(set (match_operand:SWIM248 1 "register_operand" "=&d")
|
||||
(umod:SWIM248 (match_dup 2) (match_dup 3)))
|
||||
(clobber (reg:CC FLAGS_REG))]
|
||||
""
|
||||
"#"
|
||||
"reload_completed"
|
||||
[(set (match_dup 1) (const_int 0))
|
||||
(parallel [(set (match_dup 0)
|
||||
(udiv:SWIM248 (match_dup 2) (match_dup 3)))
|
||||
(set (match_dup 1)
|
||||
(umod:SWIM248 (match_dup 2) (match_dup 3)))
|
||||
(use (match_dup 1))
|
||||
(clobber (reg:CC FLAGS_REG))])]
|
||||
""
|
||||
[(set_attr "type" "multi")
|
||||
(set_attr "mode" "<MODE>")])
|
||||
|
||||
(define_insn "*udivmod<mode>4_noext"
|
||||
[(set (match_operand:SWIM248 0 "register_operand" "=a")
|
||||
(udiv:SWIM248 (match_operand:SWIM248 2 "register_operand" "0")
|
||||
@ -7468,6 +7411,63 @@
|
||||
[(set_attr "type" "idiv")
|
||||
(set_attr "mode" "<MODE>")])
|
||||
|
||||
(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]));
|
||||
|
||||
/* 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);
|
||||
|
||||
mod = gen_rtx_UMOD (QImode, operands[1], operands[2]);
|
||||
set_unique_reg_note (insn, REG_EQUAL, mod);
|
||||
|
||||
/* Extract quotient from AL. */
|
||||
insn = emit_move_insn (operands[0], gen_lowpart (QImode, tmp0));
|
||||
|
||||
div = gen_rtx_UDIV (QImode, operands[1], operands[2]);
|
||||
set_unique_reg_note (insn, REG_EQUAL, div);
|
||||
|
||||
DONE;
|
||||
})
|
||||
|
||||
(define_insn "udivmodhiqi3"
|
||||
[(set (match_operand:HI 0 "register_operand" "=a")
|
||||
(ior:HI
|
||||
(ashift:HI
|
||||
(zero_extend:HI
|
||||
(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
|
||||
(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"
|
||||
[(set_attr "type" "idiv")
|
||||
(set_attr "mode" "QI")])
|
||||
|
||||
;; We cannot use div/idiv for double division, because it causes
|
||||
;; "division by zero" on the overflow and that's not what we expect
|
||||
;; from truncate. Because true (non truncating) double division is
|
||||
|
Loading…
x
Reference in New Issue
Block a user