diff options
author | rth <rth@138bc75d-0d04-0410-961f-82ee72b054a4> | 2009-12-08 23:39:20 +0000 |
---|---|---|
committer | rth <rth@138bc75d-0d04-0410-961f-82ee72b054a4> | 2009-12-08 23:39:20 +0000 |
commit | 9b8af75b6ab1680c69df8fe34d5c51cdc5f713a7 (patch) | |
tree | 03a371ed0efdfeaa97c661a2f063a8779fa112b7 /gcc/combine.c | |
parent | 2e5e20e16051a2eb49bfdbd315374c02386595ad (diff) | |
download | gcc-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.c | 62 |
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); } } |