llvm / llvm/llvm-project

[Polly] Potential Miscompilation in LLVM Polly with [[assume]] attributes

Open
#192,618 1 comment 0 reactions 0 assignees View on GitHub
polly
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.