diff options
author | Jakub Jelinek <jakub@redhat.com> | 2020-12-11 11:10:17 +0100 |
---|---|---|
committer | Jakub Jelinek <jakub@redhat.com> | 2020-12-11 11:10:17 +0100 |
commit | 3e60ddeb8220ed388819bb3f14e8caa9309fd3c2 (patch) | |
tree | 68ee16eb872a982e6b92cacd5bb660f493f4457a /gcc/expr.c | |
parent | 499651e43854ea65303eb55324263c25256c9735 (diff) | |
download | gcc-3e60ddeb8220ed388819bb3f14e8caa9309fd3c2.zip gcc-3e60ddeb8220ed388819bb3f14e8caa9309fd3c2.tar.gz gcc-3e60ddeb8220ed388819bb3f14e8caa9309fd3c2.tar.bz2 |
expansion: Sign or zero extend on MEM_REF stores into SUBREG with SUBREG_PROMOTED_VAR_P [PR98190]
Some targets decide to promote certain scalar variables to wider mode,
so their DECL_RTL is a SUBREG with SUBREG_PROMOTED_VAR_P.
When storing to such vars, store_expr takes care of sign or zero extending,
but if we store e.g. through MEM_REF into them, no sign or zero extension
happens and that leads to wrong-code e.g. on the following testcase on
aarch64-linux.
The following patch uses store_expr if we overwrite all the bits and it is
not reversed storage order, i.e. something that store_expr handles normally,
and otherwise (if the most significant bit is (or for pdp11 might be, but
pdp11 doesn't promote) being modified), the code extends manually.
2020-12-11 Jakub Jelinek <jakub@redhat.com>
PR middle-end/98190
* expr.c (expand_assignment): If to_rtx is a promoted SUBREG,
ensure sign or zero extension either through use of store_expr
or by extending manually.
* gcc.dg/pr98190.c: New test.
Diffstat (limited to 'gcc/expr.c')
-rw-r--r-- | gcc/expr.c | 24 |
1 files changed, 24 insertions, 0 deletions
@@ -5451,6 +5451,30 @@ expand_assignment (tree to, tree from, bool nontemporal) mode1, to_rtx, to, from, reversep)) result = NULL; + else if (SUBREG_P (to_rtx) + && SUBREG_PROMOTED_VAR_P (to_rtx)) + { + /* If to_rtx is a promoted subreg, we need to zero or sign + extend the value afterwards. */ + if (TREE_CODE (to) == MEM_REF + && !REF_REVERSE_STORAGE_ORDER (to) + && known_eq (bitpos, 0) + && known_eq (bitsize, GET_MODE_BITSIZE (GET_MODE (to_rtx)))) + result = store_expr (from, to_rtx, 0, nontemporal, false); + else + { + rtx to_rtx1 + = lowpart_subreg (subreg_unpromoted_mode (to_rtx), + SUBREG_REG (to_rtx), + subreg_promoted_mode (to_rtx)); + result = store_field (to_rtx1, bitsize, bitpos, + bitregion_start, bitregion_end, + mode1, from, get_alias_set (to), + nontemporal, reversep); + convert_move (SUBREG_REG (to_rtx), to_rtx1, + SUBREG_PROMOTED_SIGN (to_rtx)); + } + } else result = store_field (to_rtx, bitsize, bitpos, bitregion_start, bitregion_end, |