summaryrefslogtreecommitdiff
path: root/gcc/combine.c
diff options
context:
space:
mode:
authorrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>2009-12-08 23:39:20 +0000
committerrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>2009-12-08 23:39:20 +0000
commit9b8af75b6ab1680c69df8fe34d5c51cdc5f713a7 (patch)
tree03a371ed0efdfeaa97c661a2f063a8779fa112b7 /gcc/combine.c
parent2e5e20e16051a2eb49bfdbd315374c02386595ad (diff)
downloadgcc-9b8af75b6ab1680c69df8fe34d5c51cdc5f713a7.tar.gz
* combine.c (setup_incoming_promotions): Fix sign-extend of
zero-extend case; tidy conditions. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@155095 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/combine.c')
-rw-r--r--gcc/combine.c62
1 files changed, 33 insertions, 29 deletions
diff --git a/gcc/combine.c b/gcc/combine.c
index f26b9e50abc..2c60ae5640f 100644
--- a/gcc/combine.c
+++ b/gcc/combine.c
@@ -1343,7 +1343,7 @@ setup_incoming_promotions (rtx first)
for (arg = DECL_ARGUMENTS (current_function_decl); arg;
arg = TREE_CHAIN (arg))
{
- rtx reg = DECL_INCOMING_RTL (arg);
+ rtx x, reg = DECL_INCOMING_RTL (arg);
int uns1, uns3;
enum machine_mode mode1, mode2, mode3, mode4;
@@ -1375,34 +1375,38 @@ setup_incoming_promotions (rtx first)
/* The mode of the register in which the argument is being passed. */
mode4 = GET_MODE (reg);
- /* Eliminate sign extensions in the callee when possible. Only
- do this when:
- (a) A mode promotion has occurred;
- (b) The mode of the register is the same as the mode of
- the argument as it is passed; and
- (c) Either there's no language level extension, or the extension
- from source to end result is valid. The later case is true
- when the signedness of the extensions match, or when the
- language level extension is unsigned. In the later case,
- a zero extension followed by a sign extension is the same
- as one big zero extension.
- (d) When no language-level promotions (which we cannot guarantee
- will have been done by an external caller) are necessary,
- unless we know that this function is only ever called from
- the current compilation unit -- all of whose call sites will
- do the mode1 --> mode2 promotion. */
- if (mode1 != mode3
- && mode3 == mode4
- && (mode1 == mode2 || ((uns1 || !uns3) && strictly_local)))
- {
- /* Record that the value was promoted from mode1 to mode3,
- so that any sign extension at the head of the current
- function may be eliminated. */
- rtx x;
- x = gen_rtx_CLOBBER (mode1, const0_rtx);
- x = gen_rtx_fmt_e ((uns3 ? ZERO_EXTEND : SIGN_EXTEND), mode3, x);
- record_value_for_reg (reg, first, x);
- }
+ /* Eliminate sign extensions in the callee when:
+ (a) A mode promotion has occurred; */
+ if (mode1 == mode3)
+ continue;
+ /* (b) The mode of the register is the same as the mode of
+ the argument as it is passed; */
+ if (mode3 != mode4)
+ continue;
+ /* (c) There's no language level extension; */
+ if (mode1 == mode2)
+ ;
+ /* (c.1) All callers are from the current compilation unit. If that's
+ the case we don't have to rely on an ABI, we only have to know
+ what we're generating right now, and we know that we will do the
+ mode1 to mode2 promotion with the given sign. */
+ else if (!strictly_local)
+ continue;
+ /* (c.2) The combination of the two promotions is useful. This is
+ true when the signs match, or if the first promotion is unsigned.
+ In the later case, (sign_extend (zero_extend x)) is the same as
+ (zero_extend (zero_extend x)), so make sure to force UNS3 true. */
+ else if (uns1)
+ uns3 = true;
+ else if (uns3)
+ continue;
+
+ /* Record that the value was promoted from mode1 to mode3,
+ so that any sign extension at the head of the current
+ function may be eliminated. */
+ x = gen_rtx_CLOBBER (mode1, const0_rtx);
+ x = gen_rtx_fmt_e ((uns3 ? ZERO_EXTEND : SIGN_EXTEND), mode3, x);
+ record_value_for_reg (reg, first, x);
}
}