aboutsummaryrefslogtreecommitdiff
path: root/gcc/ifcvt.c
diff options
context:
space:
mode:
authorNathan Froyd <froydnj@codesourcery.com>2010-10-20 20:15:07 +0000
committerNathan Froyd <froydnj@gcc.gnu.org>2010-10-20 20:15:07 +0000
commit582346ed66a6dc53e22426ae66d01d935e3595bc (patch)
tree6a8239d64dc65925957fb1ccbe0060db0f992701 /gcc/ifcvt.c
parentab177ad53847e22cc5aaf10ffc319060c633cc4f (diff)
downloadgcc-582346ed66a6dc53e22426ae66d01d935e3595bc.zip
gcc-582346ed66a6dc53e22426ae66d01d935e3595bc.tar.gz
gcc-582346ed66a6dc53e22426ae66d01d935e3595bc.tar.bz2
ifcvt.c (noce_emit_cmove): If both of the values are SUBREGs...
* ifcvt.c (noce_emit_cmove): If both of the values are SUBREGs, try emitting the conditional move in the inner mode of the SUBREG. From-SVN: r165735
Diffstat (limited to 'gcc/ifcvt.c')
-rw-r--r--gcc/ifcvt.c63
1 files changed, 59 insertions, 4 deletions
diff --git a/gcc/ifcvt.c b/gcc/ifcvt.c
index eb96182..15f76e3 100644
--- a/gcc/ifcvt.c
+++ b/gcc/ifcvt.c
@@ -1337,6 +1337,9 @@ static rtx
noce_emit_cmove (struct noce_if_info *if_info, rtx x, enum rtx_code code,
rtx cmp_a, rtx cmp_b, rtx vfalse, rtx vtrue)
{
+ rtx target;
+ int unsignedp;
+
/* If earliest == jump, try to build the cmove insn directly.
This is helpful when combine has created some complex condition
(like for alpha's cmovlbs) that we can't hope to regenerate
@@ -1371,10 +1374,62 @@ noce_emit_cmove (struct noce_if_info *if_info, rtx x, enum rtx_code code,
return NULL_RTX;
#if HAVE_conditional_move
- return emit_conditional_move (x, code, cmp_a, cmp_b, VOIDmode,
- vtrue, vfalse, GET_MODE (x),
- (code == LTU || code == GEU
- || code == LEU || code == GTU));
+ unsignedp = (code == LTU || code == GEU
+ || code == LEU || code == GTU);
+
+ target = emit_conditional_move (x, code, cmp_a, cmp_b, VOIDmode,
+ vtrue, vfalse, GET_MODE (x),
+ unsignedp);
+ if (target)
+ return target;
+
+ /* We might be faced with a situation like:
+
+ x = (reg:M TARGET)
+ vtrue = (subreg:M (reg:N VTRUE) BYTE)
+ vfalse = (subreg:M (reg:N VFALSE) BYTE)
+
+ We can't do a conditional move in mode M, but it's possible that we
+ could do a conditional move in mode N instead and take a subreg of
+ the result.
+
+ If we can't create new pseudos, though, don't bother. */
+ if (reload_completed)
+ return NULL_RTX;
+
+ if (GET_CODE (vtrue) == SUBREG && GET_CODE (vfalse) == SUBREG)
+ {
+ rtx reg_vtrue = SUBREG_REG (vtrue);
+ rtx reg_vfalse = SUBREG_REG (vfalse);
+ unsigned int byte_vtrue = SUBREG_BYTE (vtrue);
+ unsigned int byte_vfalse = SUBREG_BYTE (vfalse);
+ rtx promoted_target;
+
+ if (GET_MODE (reg_vtrue) != GET_MODE (reg_vfalse)
+ || byte_vtrue != byte_vfalse
+ || (SUBREG_PROMOTED_VAR_P (vtrue)
+ != SUBREG_PROMOTED_VAR_P (vfalse))
+ || (SUBREG_PROMOTED_UNSIGNED_P (vtrue)
+ != SUBREG_PROMOTED_UNSIGNED_P (vfalse)))
+ return NULL_RTX;
+
+ promoted_target = gen_reg_rtx (GET_MODE (reg_vtrue));
+
+ target = emit_conditional_move (promoted_target, code, cmp_a, cmp_b,
+ VOIDmode, reg_vtrue, reg_vfalse,
+ GET_MODE (reg_vtrue), unsignedp);
+ /* Nope, couldn't do it in that mode either. */
+ if (!target)
+ return NULL_RTX;
+
+ target = gen_rtx_SUBREG (GET_MODE (vtrue), promoted_target, byte_vtrue);
+ SUBREG_PROMOTED_VAR_P (target) = SUBREG_PROMOTED_VAR_P (vtrue);
+ SUBREG_PROMOTED_UNSIGNED_SET (target, SUBREG_PROMOTED_UNSIGNED_P (vtrue));
+ emit_move_insn (x, target);
+ return x;
+ }
+ else
+ return NULL_RTX;
#else
/* We'll never get here, as noce_process_if_block doesn't call the
functions involved. Ifdef code, however, should be discouraged