In the following, the conversion to long long requires a zero extend, however the expanders use an arithmetic right shift to generate the high-part word. long long dohash(unsigned x) { return ((long long)x) << 4; } On ARM this generates mov r1, r0 lsl r0, r0, #4 asr r1, r1, #28 // Should be lsr bx lr Similarly on MIPS: sll $3,$4,4 .set noreorder .set nomacro jr $31 sra $2,$4,28 // should be srl Possibly introduced by this patch: r227018 Author: jiwang <jiwang@138bc75d-0d04-0410-961f-82ee72b054a4> Date: Wed Aug 19 22:55:28 2015 +0000 [Patch][expand] Check gimple statement to improve LSHIFT_EXP expand This patch improves LSHIFT_EXP expand if the shift operand comes from sign extension and the shift result across word_mode_size boundary. See code comments for details. 2015-08-19 Jiong.Wang <jiong.wang@arm.com> gcc/ * expr.c (expand_expr_real_2): Check gimple statement during LSHIFT_EXPR expand.
Confirmed. This also fails on 64-bit targets, eg. on AArch64: __int128 f2(unsigned long x) { return (__int128)x << 4; } mov x1, x0 lsl x0, x0, 4 asr x1, x1, 60 ret
Author: rearnsha Date: Thu Jan 19 10:35:38 2017 New Revision: 244613 URL: https://gcc.gnu.org/viewcvs?rev=244613&root=gcc&view=rev Log: [expand] Fix for PR rtl-optimization/79121 incorrect expansion of extend plus left shift When generating a shift from an extended value moving from one to two machine registers, the type of the right shift is for the most significant word should be determined by the signedness of the inner type, not the signedness of the result type. gcc: 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. gcc/testsuite: * gcc.c-torture/execute/pr79121.c: New test. Added: trunk/gcc/testsuite/gcc.c-torture/execute/pr79121.c Modified: trunk/gcc/ChangeLog trunk/gcc/expr.c trunk/gcc/testsuite/ChangeLog
Fixed on trunk. Backport to gcc-6 still needed.
Author: rearnsha Date: Fri Jan 20 11:43:58 2017 New Revision: 244702 URL: https://gcc.gnu.org/viewcvs?rev=244702&root=gcc&view=rev Log: [expand] Fix for PR rtl-optimization/79121 incorrect expansion of extend plus left shift When generating a shift from an extended value moving from one to two machine registers, the type of the right shift is for the most significant word should be determined by the signedness of the inner type, not the signedness of the result type. gcc: 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. gcc/testsuite: * gcc.c-torture/execute/pr79121.c: New test. Added: branches/gcc-6-branch/gcc/testsuite/gcc.c-torture/execute/pr79121.c Modified: branches/gcc-6-branch/gcc/ChangeLog branches/gcc-6-branch/gcc/expr.c branches/gcc-6-branch/gcc/testsuite/ChangeLog
Fixed on gcc-6 and trunk.