diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/expr.c | 40 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/testsuite/gcc.c-torture/execute/pr79121.c | 34 |
4 files changed, 72 insertions, 13 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f953791..bb725d6 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2017-01-19 Richard Earnshaw <rearnsha@arm.com> + + PR rtl-optimization/79121 + * expr.c (expand_expr_real_2, case LSHIFT_EXPR): Look at the signedness + of the inner type when shifting an extended value. + 2017-01-17 Jan Hubicka <hubicka@ucw.cz> PR lto/78407 @@ -9056,9 +9056,9 @@ expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode, /* Left shift optimization when shifting across word_size boundary. - If mode == GET_MODE_WIDER_MODE (word_mode), then normally there isn't - native instruction to support this wide mode left shift. Given below - scenario: + If mode == GET_MODE_WIDER_MODE (word_mode), then normally + there isn't native instruction to support this wide mode + left shift. Given below scenario: Type A = (Type) B << C @@ -9067,10 +9067,11 @@ expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode, | word_size | - If the shift amount C caused we shift B to across the word size - boundary, i.e part of B shifted into high half of destination - register, and part of B remains in the low half, then GCC will use - the following left shift expand logic: + If the shift amount C caused we shift B to across the word + size boundary, i.e part of B shifted into high half of + destination register, and part of B remains in the low + half, then GCC will use the following left shift expand + logic: 1. Initialize dest_low to B. 2. Initialize every bit of dest_high to the sign bit of B. @@ -9080,20 +9081,30 @@ expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode, 5. Logic right shift D by (word_size - C). 6. Or the result of 4 and 5 to finalize dest_high. - While, by checking gimple statements, if operand B is coming from - signed extension, then we can simplify above expand logic into: + While, by checking gimple statements, if operand B is + coming from signed extension, then we can simplify above + expand logic into: 1. dest_high = src_low >> (word_size - C). 2. dest_low = src_low << C. - We can use one arithmetic right shift to finish all the purpose of - steps 2, 4, 5, 6, thus we reduce the steps needed from 6 into 2. */ + We can use one arithmetic right shift to finish all the + purpose of steps 2, 4, 5, 6, thus we reduce the steps + needed from 6 into 2. + + The case is similar for zero extension, except that we + initialize dest_high to zero rather than copies of the sign + bit from B. Furthermore, we need to use a logical right shift + in this case. + + The choice of sign-extension versus zero-extension is + determined entirely by whether or not B is signed and is + independent of the current setting of unsignedp. */ temp = NULL_RTX; if (code == LSHIFT_EXPR && target && REG_P (target) - && ! unsignedp && mode == GET_MODE_WIDER_MODE (word_mode) && GET_MODE_SIZE (mode) == 2 * GET_MODE_SIZE (word_mode) && TREE_CONSTANT (treeop1) @@ -9114,6 +9125,8 @@ expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode, rtx_insn *seq, *seq_old; unsigned int high_off = subreg_highpart_offset (word_mode, mode); + bool extend_unsigned + = TYPE_UNSIGNED (TREE_TYPE (gimple_assign_rhs1 (def))); rtx low = lowpart_subreg (word_mode, op0, mode); rtx dest_low = lowpart_subreg (word_mode, target, mode); rtx dest_high = simplify_gen_subreg (word_mode, target, @@ -9125,7 +9138,8 @@ expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode, start_sequence (); /* dest_high = src_low >> (word_size - C). */ temp = expand_variable_shift (RSHIFT_EXPR, word_mode, low, - rshift, dest_high, unsignedp); + rshift, dest_high, + extend_unsigned); if (temp != dest_high) emit_move_insn (dest_high, temp); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index e639b5d..dc54c0a 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2017-01-19 Richard Earnshaw <rearnsha@arm.com> + + PR rtl-optimization/79121 + * gcc.c-torture/execute/pr79121.c: New test. + 2017-01-18 Michael Meissner <meissner@linux.vnet.ibm.com> * gcc.target/powerpc/p9-xxbr-1.c: Fix typos in submission. diff --git a/gcc/testsuite/gcc.c-torture/execute/pr79121.c b/gcc/testsuite/gcc.c-torture/execute/pr79121.c new file mode 100644 index 0000000..9fca7fb --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/pr79121.c @@ -0,0 +1,34 @@ +extern void abort (void); + +__attribute__ ((noinline, noclone)) unsigned long long f1 (int x) +{ + return ((unsigned long long) x) << 4; +} + +__attribute__ ((noinline, noclone)) long long f2 (unsigned x) +{ + return ((long long) x) << 4; +} + +__attribute__ ((noinline, noclone)) unsigned long long f3 (unsigned x) +{ + return ((unsigned long long) x) << 4; +} + +__attribute__ ((noinline, noclone)) long long f4 (int x) +{ + return ((long long) x) << 4; +} + +int main () +{ + if (f1 (0xf0000000) != 0xffffffff00000000) + abort (); + if (f2 (0xf0000000) != 0xf00000000) + abort (); + if (f3 (0xf0000000) != 0xf00000000) + abort (); + if (f4 (0xf0000000) != 0xffffffff00000000) + abort (); + return 0; +} |