https://gcc.gnu.org/bugzilla/show_bug.cgi?id=119040
--- Comment #2 from Jeevitha <jeevitha at gcc dot gnu.org> ---
For the following testcase:
#include <altivec.h>
vector signed int without_sel(vector signed int l, vector signed int r) {
vector signed int mask = {63, 63, 63, 63};
l = l & ~mask;
l |= r & mask;
return l;
}
Current trunk emits:
xxspltiw %vs0,63
xxspltiw %vs32,4294967232
xxlor %vs33,%vs34,%vs34
xxland %vs35,%vs35,%vs0
vand %v2,%v0,%v1
vor %v2,%v2,%v3
blr
This sequence performs (l & ~mask) | (r & mask), which is a standard bitfield
merge pattern with non-overlapping masks.
Ideally, this should be optimized into a vsel instruction (e.g., vec_sel(l, r,
mask)).
Currently, GCC fails to combine this pattern into altivec_vsel<mode>* because
it treats the two masks (mask and ~mask) independently and does not detect that
they are complementary.
Dump before combine:
2: r120:V4SI = %2:V4SI
4: r122:V4SI = %4:V4SI
11: r123:V4SI = const_vector(const_int -64)
12: r118:V4SI = r120:V4SI & r123:V4SI
17: r126:V4SI = const_vector(const_int 63)
18: r125:V4SI = r122:V4SI & r126:V4SI
19: r124:V4SI = r125:V4SI | r118:V4SI