[Polly] Potential Miscompilation in LLVM Polly with [[assume]] attributes
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
Reproducer: https://godbolt.org/z/shYKjM14W
I have probably encountered a potential miscompilation problem in LLVM's Polly optimization passes when handling complex loop nests involving C++23 [[assume]] attributes.
To ensure that the assumptions are valid and do not introduce UBs, the code includes a `VALID` macro. When compiled with `-DVALID`, these assumptions are transformed into standard assert calls. Running the program with -DVALID passes all assertions successfully.
Compiler version:
```
clang version 23.0.0git (https://github.com/llvm/llvm-project.git ac2c986c5830b6c413ddbb0e75b8c1399fdffe85)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /data/lenovo/compiler-build/llvm/llvm-project/build/bin
Build config: +assertions
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/13
Selected GCC installation: /usr/lib/gcc/x86_64-linux-gnu/13
Candidate multilib: .;@m64
Selected multilib: .;@m64
```
Steps to reproduce:
`$ cat dri.cpp`
```c
#include
#include
#ifndef VALID
#define ASSUMPTION(x) [[assume(x)]];
#else
#include
#define ASSUMPTION(x) assert(x);
#endif
unsigned long long int seed = 0;
void hash(unsigned long long int *seed, unsigned long long int const v) {
*seed ^= v + 0x9e3779b9 + ((*seed)<<6) + ((*seed)>>2);
}
unsigned int var_0 = 2691527292U;
short var_6 = (short)10965;
short var_7 = (short)-24742;
unsigned long long int var_9 = 10100325111651034363ULL;
long long int var_11 = 9129607831676078010LL;
unsigned long long int var_17 = 16131695589169633005ULL;
long long int var_19 = 7048563116518992808LL;
unsigned short arr_6 [23] [23] ;
long long int arr_7 [23] [23] ;
unsigned short arr_10 [23] [23] [23] ;
unsigned short arr_11 [23] [23] [23] ;
unsigned short arr_16 [23] ;
unsigned int arr_18 [23] [23] [23] ;
short arr_20 [23] [23] [23] ;
unsigned long long int arr_21 [23] [23] [23] ;
unsigned int arr_22 [23] [23] [23] ;
unsigned short arr_24 [23] [23] [23] ;
void init() {
for (size_t i = 0; i < 23; ++i) {
arr_16[i] = (unsigned short)40877;
for (size_t j = 0; j < 23; ++j) {
arr_6[i][j] = (unsigned short)48318;
arr_7[i][j] = -230513857038758231LL;
for (size_t k = 0; k < 23; ++k) {
arr_10[i][j][k] = (unsigned short)62907;
arr_11[i][j][k] = (unsigned short)15619;
arr_18[i][j][k] = 2069756154U;
arr_20[i][j][k] = (short)1567;
arr_21[i][j][k] = 17555796784628800565ULL;
arr_22[i][j][k] = 1035966794U;
arr_24[i][j][k] = (unsigned short)12834;
}
}
}
}
void checksum() {
hash(&seed, var_17);
hash(&seed, var_19);
}
void test(long long int arr_7 [23] [23]){
for (long long int i_1 = 0LL; i_1 < 23LL; i_1 += 2LL)
{
for (bool i_2 = ((((int) ((bool) var_11 ))) - (1)); i_2 < ((int) ((bool) var_0 )); i_2 += (bool)1)
{
{
for (short i_3 = ((((int) ((short) ((((bool) (((bool)1) ? (595892763U) : (((unsigned int) ((int) (short)-1)))))) ? (((((bool) arr_6 [i_1] [i_2])) ? (((int) arr_10 [i_1] [i_1] [i_1])) : (((int) arr_6 [i_2] [i_1])))) : (((((bool) (unsigned short)604)) ? (((int) arr_10 [i_1] [i_1] [i_2])) : (((int) arr_6 [i_1] [i_2])))))))) + (2629)); i_3 < (short)23; i_3 += (short)1)
{
ASSUMPTION((unsigned short)(((((int) ((unsigned short) var_7 ))) - (40792))) == (unsigned short)(2));
ASSUMPTION((unsigned short)(((((int) ((unsigned short) ((long long int) (!(((bool) arr_11 [i_1] [i_1] [i_1]))))))) + (1))) == (unsigned short)(1));
for (unsigned short i_4 = ((((int) ((unsigned short) var_7 ))) - (40792)); i_4 < ((((int) ((unsigned short) std::min((((int) arr_16 [i_1])), ((((62606)) ? (((int) var_6 )) : (((int) (short)23767)))))))) - (10943)); i_4 += ((((int) ((unsigned short) ((long long int) (!(((bool) arr_11 [i_1] [i_1] [i_1]))))))) + (1)))
{
for (unsigned short i_5 = ((((int) ((unsigned short) ((bool) var_9 )))) - (1)); i_5 < (((23320)) - (23297)); i_5 += (unsigned short)4)
{
{
var_17 = ((((bool) std::min((((long long int) ((short) -6432971229467870064LL))), ((((9129607831676078010LL)) ? (arr_7 [i_4] [i_4]) : (((long long int) (9023)))))))) ? (((unsigned long long int) ((((bool) ((((bool) var_9 )) ? (9129607831676078010LL) : (((long long int) ((int) (unsigned short)10510)))))) ? (((int) arr_10 [i_4 + 1] [(unsigned short)19] [i_3])) : (((int) arr_20 [i_4 - 1] [i_4 - 1] [i_4 - 1]))))) : (((((bool) arr_16 [i_4 - 2])) ? (((((unsigned long long int) (10965))) & (var_9 ))) : (((((bool) arr_18 [21U] [i_2] [i_2])) ? (((unsigned long long int) (10965))) : (var_9 ))))));
var_19 = ((long long int) std::min((var_19 ), (((long long int) ((((bool) arr_24 [4LL] [4LL] [i_1])) ? (((int) ((bool) (-((44834)))))) : (((int) ((bool) ((((bool) -1)) ? (arr_21 [i_2] [i_2] [i_5]) : (((unsigned long long int) arr_22 [i_1] [i_2] [i_2])))))))))));
}
}
}
}
}
}
}
}
int main() {
init();
test( arr_7 );
checksum();
printf("%llu\n", seed);
}
```
```console
$ clang dri.cpp && ./a.out
175252250083
$ clang dri.cpp -mllvm -polly -O3 && ./a.out
5639367760297730988
$ clang dri.cpp -DVALID -fsanitize=undefined && ./a.out
175252250083
```
Attached preprocessed file:
[dri-preproc.cpp](https://github.com/user-attachments/files/26817685/dri-preproc.cpp)
Contributor guide
Research direction
Start with the attached reproducer in dri.cpp or dri-preproc.cpp and run the three clang commands shown in the issue, comparing the checksum output with and without -mllvm -polly -O3. Then trace the Polly optimization passes handling the loop nest and [[assume]] attributes. Done means identifying and fixing the miscompilation while preserving the matching output and passing the VALID assertion run.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 48/100