llvm-project
llvm-project copied to clipboard
[ARM][BUG] Run bad result for vect_type in arm32be
https://godbolt.org/z/vYKsfos5o
typedef short int SV __attribute__((vector_size(16)));
extern void abort(void);
__attribute__((noinline)) void vec_div(SV *x, SV *y)
{
*x = *y / ((SV){1, 4, 2, 8, 16, 64, 32, 128});
}
SV s[] = {
((SV){73, -9123, 32761, 8191, 16371, 1201, 12701, 9999}),
((SV){9903, -1, -7323, 0, -7, -323, 9124, -9199})
};
int main()
{
SV sr, sr2;
int i;
for (i = 0; i < sizeof(s) / sizeof(s[0]); i++) {
vec_div(&sr, s + i);
if (sr[0] != s[i][0] / 1 || sr[3] != s[i][3] / 8)
abort();
asm volatile("" : : "r"(&sr) : "memory");
}
return 0;
}
The expected sr is
[73, -2280, 16380, 1023, 1023, 18, 396, 78]
the result is
[-2280, 73, 1023, 16380, 18, 1023, 78, 396]
I guess rev instruction is misused.
(The vectorize for big endian mode in llvm use rev to handle byte ordering, and introduces many rev instrution, also some bugs.
https://llvm.org/docs/BigEndianNEON.html)
@llvm/issue-subscribers-backend-arm
Author: None (hstk30-hw)
typedef short int SV __attribute__((vector_size(16)));
extern void abort(void);
__attribute__((noinline)) void vec_div(SV *x, SV *y)
{
*x = *y / ((SV){1, 4, 2, 8, 16, 64, 32, 128});
}
SV s[] = {
((SV){73, -9123, 32761, 8191, 16371, 1201, 12701, 9999}),
((SV){9903, -1, -7323, 0, -7, -323, 9124, -9199})
};
int main()
{
SV sr, sr2;
int i;
for (i = 0; i < sizeof(s) / sizeof(s[0]); i++) {
vec_div(&sr, s + i);
if (sr[0] != s[i][0] / 1 || sr[3] != s[i][3] / 8)
abort();
asm volatile("" : : "r"(&sr) : "memory");
}
return 0;
}
The expected sr is
[73, -2280, 16380, 1023, 1023, 18, 396, 78]
the result is
[-2280, 73, 1023, 16380, 18, 1023, 78, 396]
I guess rev instruction is misused.
(The vectorize for big endian mode in llvm use rev to handle byte ordering, and introduces many rev instrution, also some bugs.
https://llvm.org/docs/BigEndianNEON.html)
@llvm/issue-subscribers-bug
Author: None (hstk30-hw)
typedef short int SV __attribute__((vector_size(16)));
extern void abort(void);
__attribute__((noinline)) void vec_div(SV *x, SV *y)
{
*x = *y / ((SV){1, 4, 2, 8, 16, 64, 32, 128});
}
SV s[] = {
((SV){73, -9123, 32761, 8191, 16371, 1201, 12701, 9999}),
((SV){9903, -1, -7323, 0, -7, -323, 9124, -9199})
};
int main()
{
SV sr, sr2;
int i;
for (i = 0; i < sizeof(s) / sizeof(s[0]); i++) {
vec_div(&sr, s + i);
if (sr[0] != s[i][0] / 1 || sr[3] != s[i][3] / 8)
abort();
asm volatile("" : : "r"(&sr) : "memory");
}
return 0;
}
The expected sr is
[73, -2280, 16380, 1023, 1023, 18, 396, 78]
the result is
[-2280, 73, 1023, 16380, 18, 1023, 78, 396]
I guess rev instruction is misused.
(The vectorize for big endian mode in llvm use rev to handle byte ordering, and introduces many rev instrution, also some bugs.
https://llvm.org/docs/BigEndianNEON.html)
Hi - The last vrev64.32 looks suspicious. There is a call to bitcast here: https://github.com/llvm/llvm-project/blob/74984dee51307779a3eab10a8cd6102be37e1081/llvm/lib/Target/ARM/ARMISelLowering.cpp#L14801, that should probably be an nvcast / ARMISD::VECTOR_REG_CAST instead.
Thx bro, the last vrev64.32 should be vrev64.16. I'll fix it.
Fixed it.
Hi - The last vrev64.32 looks suspicious. There is a call to bitcast here:
https://github.com/llvm/llvm-project/blob/74984dee51307779a3eab10a8cd6102be37e1081/llvm/lib/Target/ARM/ARMISelLowering.cpp#L14801
, that should probably be an nvcast / ARMISD::VECTOR_REG_CAST instead.
Hi, I have a question. Is there any other BITCAST should be ARMISD::VECTOR_REG_CAST in ARMISelLowering.cpp?
All bitcasts of the vector type need to be converted, is that right?
for example: https://github.com/llvm/llvm-project/blob/74984dee51307779a3eab10a8cd6102be37e1081/llvm/lib/Target/ARM/ARMISelLowering.cpp#L6331
There might well be other places where this is wrong for sure. It shouldn't matter in others though. If the element size is there same then there should not be a differences between the two operations IIRC, and if the value is all zeros (as in getZeroVector), then it would still be all-zeroes after a bitcast/VECTOR_REG_CAST.