https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63321
Bug ID: 63321 Summary: [SH] Unused T bit result of shll / shlr insns Product: gcc Version: 5.0 Status: UNCONFIRMED Severity: enhancement Priority: P3 Component: target Assignee: unassigned at gcc dot gnu.org Reporter: olegendo at gcc dot gnu.org Target: sh*-*-* The following examples resemble code that is usually used when implementing pointer tagging (storing meta info in always-zero bits of a pointer variable). The shll / shr insns shift the MSB / LSB out into the T bit. However, the T bit value is lost and redundant MSB / LSB extractions remain in the code. unsigned int foo (unsigned int); unsigned int test2 (unsigned int x) { unsigned int xx = x >> 1; if (x & 1) return foo (xx); else return xx; } /* mov r4,r1 shlr r1 mov r4,r0 tst #1,r0 bf/s .L5 mov r1,r0 rts nop .align 1 .L5: mov.l .L6,r0 jmp @r0 mov r1,r4 better: shlr r4 bt .L5 rts mov r4,r0 .L5: mov.l .L6,r0 jmp @r0 nop */ void test2_1 (unsigned int x, unsigned int* y) { y[0] = x >> 1; y[1] = x & 1; } /* mov r4,r1 mov r4,r0 shlr r1 and #1,r0 mov.l r1,@r5 rts mov.l r0,@(4,r5) better: shlr r4 movt r0 mov.l r4,@r5 rts mov.l r0,@(4,r5) */ unsigned int test3 (unsigned int x) { unsigned int xx = x << 1; if (x & (1 << 31)) return foo (xx); else return xx; } /* cmp/pz r4 mov r4,r0 bf/s .L13 add r0,r0 rts nop .align 1 .L13: mov r0,r4 mov.l .L14,r0 jmp @r0 nop better: shll r4 bt .L13 rts mov r4,r0 .L13: mov.l .L14,r0 jmp @r0 nop */ void test3_1 (unsigned int x, unsigned int* y) { y[0] = x << 1; y[1] = x >> 31; } /* mov r4,r1 shll r4 add r1,r1 movt r4 mov.l r1,@r5 rts mov.l r4,@(4,r5) better: shll r4 movt r0 mov.l r4,@r5 rts mov.l r0,@(4,r5) */ It seems that combine doesn't try to combine those adjacent insns into a parallel, which could be used to implement that kind of patterns. An alternative is to do a manual combining/peepholing of insns in the split pass after combine, as it is done for other insns.