summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorchaoyingfu <chaoyingfu@138bc75d-0d04-0410-961f-82ee72b054a4>2007-05-08 22:51:14 +0000
committerchaoyingfu <chaoyingfu@138bc75d-0d04-0410-961f-82ee72b054a4>2007-05-08 22:51:14 +0000
commit43fda2619f4b075d814e64a161fec03b09f95b9b (patch)
tree4f99bbafe98aff39b7f5885c910746129d4e95e8
parent1121ac6fd3429a1a6a31cc627adc05a0b18f644d (diff)
downloadgcc-43fda2619f4b075d814e64a161fec03b09f95b9b.tar.gz
* doc/md.texi (msub@var{m}@var{n}4, usub@var{m}@var{n}4): Document.
* optabs.h (OTI_smsub_widen, OTI_umsub_widen): New optab_indexes. (smsub_widen_optab, umsub_widen_optab): Define. * optabs.c (init_optabs): Initialize smsub_widen_optab and umsub_widen_optab. * genopinit.c (optabs): Fill in smsub_widen_optab and umsub_widen_optab. * expr.c (expand_expr_real_1): Try to use smsub_widen_optab and umsub_widen_optab to implement multiply-subtract sequences. * config/mips/mips.md (*msac<u>_di): Rename to... (<u>msubsidi4): ...this. Extend condition to include GENERATE_MADD_MSUB and TARGET_DSPR2. Change the constraint of operand 0 to "ka" and use the three-operand form of msub<u> for TARGET_DSPR2. * config/mips/mips-dspr2.md (mips_msub, mips_msubu): Convert to define_expands. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@124558 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog19
-rw-r--r--gcc/config/mips/mips-dspr2.md30
-rw-r--r--gcc/config/mips/mips.md10
-rw-r--r--gcc/doc/md.texi19
-rw-r--r--gcc/expr.c41
-rw-r--r--gcc/genopinit.c2
-rw-r--r--gcc/optabs.c2
-rw-r--r--gcc/optabs.h8
8 files changed, 103 insertions, 28 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 1d0e9055128..4c7ba636bfb 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,22 @@
+2007-05-08 Chao-ying Fu <fu@mips.com>
+
+ * doc/md.texi (msub@var{m}@var{n}4, usub@var{m}@var{n}4): Document.
+ * optabs.h (OTI_smsub_widen, OTI_umsub_widen): New optab_indexes.
+ (smsub_widen_optab, umsub_widen_optab): Define.
+ * optabs.c (init_optabs): Initialize smsub_widen_optab and
+ umsub_widen_optab.
+ * genopinit.c (optabs): Fill in smsub_widen_optab and
+ umsub_widen_optab.
+ * expr.c (expand_expr_real_1): Try to use smsub_widen_optab
+ and umsub_widen_optab to implement multiply-subtract sequences.
+ * config/mips/mips.md (*msac<u>_di): Rename to...
+ (<u>msubsidi4): ...this. Extend condition to include
+ GENERATE_MADD_MSUB and TARGET_DSPR2. Change the constraint
+ of operand 0 to "ka" and use the three-operand form of msub<u>
+ for TARGET_DSPR2.
+ * config/mips/mips-dspr2.md (mips_msub, mips_msubu): Convert
+ to define_expands.
+
2007-05-08 Kaz Kojima <kkojima@gcc.gnu.org>
PR rtl-optimization/28011
diff --git a/gcc/config/mips/mips-dspr2.md b/gcc/config/mips/mips-dspr2.md
index dd0aab553a1..20190085177 100644
--- a/gcc/config/mips/mips-dspr2.md
+++ b/gcc/config/mips/mips-dspr2.md
@@ -162,31 +162,13 @@
(match_operand:DI 1 "register_operand")))]
"TARGET_DSPR2 && !TARGET_64BIT")
-(define_insn "mips_msub"
- [(set (match_operand:DI 0 "register_operand" "=a")
- (minus:DI
- (match_operand:DI 1 "register_operand" "0")
- (mult:DI (sign_extend:DI
- (match_operand:SI 2 "register_operand" "d"))
- (sign_extend:DI
- (match_operand:SI 3 "register_operand" "d")))))]
- "TARGET_DSPR2 && !TARGET_64BIT"
- "msub\t%q0,%2,%3"
- [(set_attr "type" "imadd")
- (set_attr "mode" "SI")])
-
-(define_insn "mips_msubu"
- [(set (match_operand:DI 0 "register_operand" "=a")
+(define_expand "mips_msub<u>"
+ [(set (match_operand:DI 0 "register_operand")
(minus:DI
- (match_operand:DI 1 "register_operand" "0")
- (mult:DI (zero_extend:DI
- (match_operand:SI 2 "register_operand" "d"))
- (zero_extend:DI
- (match_operand:SI 3 "register_operand" "d")))))]
- "TARGET_DSPR2 && !TARGET_64BIT"
- "msubu\t%q0,%2,%3"
- [(set_attr "type" "imadd")
- (set_attr "mode" "SI")])
+ (match_operand:DI 1 "register_operand")
+ (mult:DI (any_extend:DI (match_operand:SI 2 "register_operand"))
+ (any_extend:DI (match_operand:SI 3 "register_operand")))))]
+ "TARGET_DSPR2 && !TARGET_64BIT")
(define_insn "mulv2hi3"
[(parallel
diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md
index e44b919ccb9..de592b9adc7 100644
--- a/gcc/config/mips/mips.md
+++ b/gcc/config/mips/mips.md
@@ -1649,16 +1649,18 @@
[(set_attr "type" "imul")
(set_attr "mode" "SI")])
-(define_insn "*msac<u>_di"
- [(set (match_operand:DI 0 "register_operand" "=x")
+(define_insn "<u>msubsidi4"
+ [(set (match_operand:DI 0 "register_operand" "=ka")
(minus:DI
(match_operand:DI 3 "register_operand" "0")
(mult:DI
(any_extend:DI (match_operand:SI 1 "register_operand" "d"))
(any_extend:DI (match_operand:SI 2 "register_operand" "d")))))]
- "!TARGET_64BIT && ISA_HAS_MSAC"
+ "!TARGET_64BIT && (ISA_HAS_MSAC || GENERATE_MADD_MSUB || TARGET_DSPR2)"
{
- if (TARGET_MIPS5500)
+ if (TARGET_DSPR2)
+ return "msub<u>\t%q0,%1,%2";
+ else if (TARGET_MIPS5500 || GENERATE_MADD_MSUB)
return "msub<u>\t%1,%2";
else
return "msac<u>\t$0,%1,%2";
diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi
index 56cc60f2e1e..53c5769f788 100644
--- a/gcc/doc/md.texi
+++ b/gcc/doc/md.texi
@@ -3687,6 +3687,25 @@ These instructions are not allowed to @code{FAIL}.
Like @code{madd@var{m}@var{n}4}, but zero-extend the multiplication
operands instead of sign-extending them.
+@cindex @code{msub@var{m}@var{n}4} instruction pattern
+@item @samp{msub@var{m}@var{n}4}
+Multiply operands 1 and 2, sign-extend them to mode @var{n}, subtract the
+result from operand 3, and store the result in operand 0. Operands 1 and 2
+have mode @var{m} and operands 0 and 3 have mode @var{n}.
+Both modes must be integer modes and @var{n} must be twice
+the size of @var{m}.
+
+In other words, @code{msub@var{m}@var{n}4} is like
+@code{mul@var{m}@var{n}3} except that it also subtracts the result
+from operand 3.
+
+These instructions are not allowed to @code{FAIL}.
+
+@cindex @code{umsub@var{m}@var{n}4} instruction pattern
+@item @samp{umsub@var{m}@var{n}4}
+Like @code{msub@var{m}@var{n}4}, but zero-extend the multiplication
+operands instead of sign-extending them.
+
@cindex @code{divmod@var{m}4} instruction pattern
@item @samp{divmod@var{m}4}
Signed division that produces both a quotient and a remainder.
diff --git a/gcc/expr.c b/gcc/expr.c
index 5a618c98398..ce26ba63a2d 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -8133,6 +8133,47 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
return REDUCE_BIT_FIELD (simplify_gen_binary (PLUS, mode, op0, op1));
case MINUS_EXPR:
+ /* Check if this is a case for multiplication and subtraction. */
+ if (TREE_CODE (type) == INTEGER_TYPE
+ && TREE_CODE (TREE_OPERAND (exp, 1)) == MULT_EXPR)
+ {
+ tree subsubexp0, subsubexp1;
+ enum tree_code code0, code1;
+
+ subexp1 = TREE_OPERAND (exp, 1);
+ subsubexp0 = TREE_OPERAND (subexp1, 0);
+ subsubexp1 = TREE_OPERAND (subexp1, 1);
+ code0 = TREE_CODE (subsubexp0);
+ code1 = TREE_CODE (subsubexp1);
+ if (code0 == NOP_EXPR && code1 == NOP_EXPR
+ && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subsubexp0, 0)))
+ < TYPE_PRECISION (TREE_TYPE (subsubexp0)))
+ && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subsubexp0, 0)))
+ == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subsubexp1, 0))))
+ && (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subsubexp0, 0)))
+ == TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subsubexp1, 0)))))
+ {
+ tree op0type = TREE_TYPE (TREE_OPERAND (subsubexp0, 0));
+ enum machine_mode innermode = TYPE_MODE (op0type);
+ bool zextend_p = TYPE_UNSIGNED (op0type);
+ this_optab = zextend_p ? umsub_widen_optab : smsub_widen_optab;
+ if (mode == GET_MODE_2XWIDER_MODE (innermode)
+ && (this_optab->handlers[(int) mode].insn_code
+ != CODE_FOR_nothing))
+ {
+ expand_operands (TREE_OPERAND (subsubexp0, 0),
+ TREE_OPERAND (subsubexp1, 0),
+ NULL_RTX, &op0, &op1, EXPAND_NORMAL);
+ op2 = expand_expr (TREE_OPERAND (exp, 0), subtarget,
+ VOIDmode, 0);
+ temp = expand_ternary_op (mode, this_optab, op0, op1, op2,
+ target, unsignedp);
+ gcc_assert (temp);
+ return REDUCE_BIT_FIELD (temp);
+ }
+ }
+ }
+
/* For initializers, we are allowed to return a MINUS of two
symbolic constants. Here we handle all cases when both operands
are constant. */
diff --git a/gcc/genopinit.c b/gcc/genopinit.c
index 992981aa8c0..a137750f948 100644
--- a/gcc/genopinit.c
+++ b/gcc/genopinit.c
@@ -87,6 +87,8 @@ static const char * const optabs[] =
"usmul_widen_optab->handlers[$B].insn_code = CODE_FOR_$(usmul$a$b3$)$N",
"smadd_widen_optab->handlers[$B].insn_code = CODE_FOR_$(madd$a$b4$)$N",
"umadd_widen_optab->handlers[$B].insn_code = CODE_FOR_$(umadd$a$b4$)$N",
+ "smsub_widen_optab->handlers[$B].insn_code = CODE_FOR_$(msub$a$b4$)$N",
+ "umsub_widen_optab->handlers[$B].insn_code = CODE_FOR_$(umsub$a$b4$)$N",
"sdiv_optab->handlers[$A].insn_code = CODE_FOR_$(div$a3$)",
"sdivv_optab->handlers[$A].insn_code = CODE_FOR_$(div$V$I$a3$)",
"udiv_optab->handlers[$A].insn_code = CODE_FOR_$(udiv$I$a3$)",
diff --git a/gcc/optabs.c b/gcc/optabs.c
index b63acccba50..416c4d43e9b 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -5442,6 +5442,8 @@ init_optabs (void)
usmul_widen_optab = init_optab (UNKNOWN);
smadd_widen_optab = init_optab (UNKNOWN);
umadd_widen_optab = init_optab (UNKNOWN);
+ smsub_widen_optab = init_optab (UNKNOWN);
+ umsub_widen_optab = init_optab (UNKNOWN);
sdiv_optab = init_optab (DIV);
sdivv_optab = init_optabv (DIV);
sdivmod_optab = init_optab (UNKNOWN);
diff --git a/gcc/optabs.h b/gcc/optabs.h
index e5bbef89e4c..60dcc159729 100644
--- a/gcc/optabs.h
+++ b/gcc/optabs.h
@@ -92,6 +92,12 @@ enum optab_index
/* Unigned multiply and add with the result and addend one machine mode
wider than the multiplicand and multiplier. */
OTI_umadd_widen,
+ /* Signed multiply and subtract the result and minuend one machine mode
+ wider than the multiplicand and multiplier. */
+ OTI_smsub_widen,
+ /* Unigned multiply and subtract the result and minuend one machine mode
+ wider than the multiplicand and multiplier. */
+ OTI_umsub_widen,
/* Signed divide */
OTI_sdiv,
@@ -317,6 +323,8 @@ extern GTY(()) optab optab_table[OTI_MAX];
#define usmul_widen_optab (optab_table[OTI_usmul_widen])
#define smadd_widen_optab (optab_table[OTI_smadd_widen])
#define umadd_widen_optab (optab_table[OTI_umadd_widen])
+#define smsub_widen_optab (optab_table[OTI_smsub_widen])
+#define umsub_widen_optab (optab_table[OTI_umsub_widen])
#define sdiv_optab (optab_table[OTI_sdiv])
#define smulv_optab (optab_table[OTI_smulv])
#define sdivv_optab (optab_table[OTI_sdivv])