Not able to vectorize struct members

Given a test case:

#define N 10
struct foo {
float a[N][N];
float b[N];
};

void compute(struct foo *p)
{
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
p->a[i][j] += 0.1f * p->b[i];
}
}
}

LLVM isn’t able to vectorize this code. I’m not sure what the issue is here as it seems to vectorize this code:

#define N 10
struct foo {
float a[N];
float b[N];
};

void compute(struct foo *p)
{
for (int i = 0; i < N; i++) {
p->a[i] += 0.1f * p->b[i];
}
}

Is this a known issue?

-Ryan

I’ve reported this here:

I see Roman has commented on the ticket. The issue is alias analysis it looks like, we have a partial fix in place in BasicAliasAnalysis.cpp:

unsigned MinNumIndex = std::min(GEP1->getNumIndices(),
GEP2->getNumIndices());
if (MinNumIndex < 2)
return MayAlias;
SmallVector<Value *, 8> IntermediateIndices;
IntermediateIndices.push_back(GEP1->getOperand(1));
// Note,
// 1. The index to struct field can only be literal constant.
// 2. So far all the struct field indexes are the same respectively.
// 3. The array indexes could be different, but they don’t matter here.
// 4. The types should be the same, say, different array indexes don’t
// matter, and the struct indexes be the same respectively.
// If current type is StructType, and the pair of corresponding indexes
// are not equal, NoAlias
for (unsigned i = 1; i != MinNumIndex - 1; ++i) {
if (isa(GetElementPtrInst::getIndexedType(
GEP1->getSourceElementType(), IntermediateIndices))) {
ConstantInt *C1 = dyn_cast(GEP1->getOperand(i + 1));
ConstantInt *C2 = dyn_cast(GEP2->getOperand(i + 1));
if (C1 && C2 && C1->getSExtValue() != C2->getSExtValue())
return NoAlias;
}
IntermediateIndices.push_back(GEP1->getOperand(i + 1));
}
}
// Note that we fall back the original logic here, there are still some thing
// not covered like p->a[2].x v.s. p->a[1].x.b[2]

but this seems to break some cases and isn’t generalized.

-Ryan

So it looks like AA is being too conservative in aliasSameBasePointerGEPs.

For example:
#define N 10
struct foo {
float a[N];//[N];
float b[N];
};

void compute(struct foo *p )
{
for (int i = 0; i < N; i++) {
p->a[i] += 0.1f * p->b[i];
}
}

vectorizes.

There is this code:

if (GEP1->getNumIndices() != GEP2->getNumIndices() ||
GEP1->getNumIndices() < 2)
{
errs()<<“1\n”;
return MayAlias;
}

which appears to return MayAlias anytime the numder of indices don’t equal each other, why? This doesn’t seem right.

Seems like this is being overly conservative. Anytime any GEPs have the same base pointer with different indices this is going to return MayAlias.

Thanks,

Ryan