Unnecessary generation of temporaries with tst type operations
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
Linaro GCC |
Triaged
|
Low
|
Unassigned |
Bug Description
Consider the following testcase.
typedef unsigned int uint32_t;
typedef unsigned long long uint64_t;
typedef unsigned long uintptr_t;
typedef unsigned short uint16_t;
void f2(char *d, char const *s, int flags)
{
uint32_t tmp0, tmp1;
if (flags & 1)
tmp0 = *s++;
if (flags & 2)
{
uint16_t *ss = (void *)s;
tmp1 = *ss++;
s = (void *)ss;
}
if (flags & 1)
*d++ = tmp0;
if (flags & 2)
{
uint16_t *dd = (void *)d;
*dd++ = tmp1;
d = (void *)dd;
}
}
GCC currently generates
push {r4, r5}
ands r5, r2, #1
it ne
ldrbne r4, [r1], #1 @ zero_extendqisi2
ands r2, r2, #2
it ne
ldrhne r3, [r1, #0]
cbz r5, .L4
strb r4, [r0], #1
.L4:
cbz r2, .L1
strh r3, [r0, #0] @ movhi
.L1:
pop {r4, r5}
bx lr
This could very well instead be :
tst r2, #1
it ne
ldrneb ip, [r1], #1 @ zero_extendqisi2
tst r2, #2
it ne
ldrneh r3, [r1, #0]
tst r2, #1
it ne
strneb ip, [r0], #1
tst r2, #2
strneh r3, [r0, #0] @ movhi
bx lr
This is also a problem on other ports given that the a & b tst operation is CSE'd and the result is compared against 0.
cheers
Ramana
tags: | added: size speed task |
Changed in gcc-linaro: | |
status: | New → Triaged |
Changed in gcc-linaro: | |
importance: | Undecided → Low |
Current upstream trunk gives the following:
ands r3, r2, #1
push {r4, r5}
itt ne
ldrbne r5, [r1, #0] @ zero_extendqisi2
addne r1, r1, #1
ands r2, r2, #2
it ne
ldrhne r4, [r1, #0]
cbz r3, .L4
strb r5, [r0, #0]
adds r0, r0, #1
.L4:
cbz r2, .L1
strh r4, [r0, #0] @ movhi
.L1:
pop {r4, r5}
bx lr
The unnecessary temporaries still exist, *and* it now fails to do the auto-increment correctly as well. :(