llvm / llvm/llvm-project

[Polly] Potential Miscompilation with -O3 -mllvm -polly in complex nested loops

Open
#192,616 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

The following code produces a different checksum result when compiled with Polly enabled vs. disabled.

Reproducer: https://godbolt.org/z/jEnPv935h

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.c`

```c
#include

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 long long int var_7 = 11138240969048749202ULL;
unsigned int var_14 = 161197919U;
unsigned short var_16 = 61832;
int zero = 0;
unsigned char var_20 = 209;
signed char var_21 = 90;
signed char var_33 = 117;
signed char var_34 = -75;
unsigned short var_36 = 37952;
unsigned int arr_1[14][14];
unsigned long long int arr_2[14][14];
unsigned long long int arr_4[14][14];
unsigned short arr_5[14][14][14];
unsigned long long int arr_6[14][14][14];
unsigned long long int arr_7[14][14][14];
signed char arr_8[14][14][14];
signed char arr_9[14][14][14];
unsigned short arr_10[14][14];

void init() {
for (size_t i = 0; i < 14; ++i) {
for (size_t j = 0; j < 14; ++j) {
arr_1[i][j] = (j % 2 == 0) ? 73739281U : 3687122762U;
arr_2[i][j] = (i % 2 == 0) ? 5317230533858951824ULL : 11557756781242853648ULL;
arr_4[i][j] = (i % 2 == 0) ? 14468468399583357002ULL : 7843331194864611391ULL;
arr_10[i][j] = 45956;
for (size_t k = 0; k < 14; ++k) {
arr_5[i][j][k] = (k % 2 == 0) ? 29666 : 33568;
arr_6[i][j][k] = (i % 2 == 0) ? 2585343244469730966ULL : 3646715633577526581ULL;
arr_7[i][j][k] = (k % 2 == 0) ? 6247015860608722573ULL : 4755595427871114276ULL;
arr_8[i][j][k] = 35;
arr_9[i][j][k] = 51;
}
}
}
}

void checksum() {
hash(&seed, var_20);
hash(&seed, var_21);
hash(&seed, var_33);
hash(&seed, var_34);
hash(&seed, var_36);
}

#define max(a,b) \
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a > _b ? _a : _b; })
#define min(a,b) \
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a < _b ? _a : _b; })

void test(unsigned long long int arr_6[14][14][14], unsigned long long int arr_7[14][14][14], signed char arr_8[14][14][14], signed char arr_9[14][14][14], unsigned short arr_10[14][14]) {
for (signed char i_0 = (signed char)0; i_0 < (signed char)14; i_0 += ((int)(signed char)(-49404) - 3)) {
for (signed char i_1 = ((int)(signed char)((_Bool)(~(0 ? 102 : (int)(short)8750)) ? ((_Bool)((_Bool)arr_2[2][i_0] ? 161197919 : (unsigned int)49404) ? (unsigned int)~(-266999352) : (1 ? arr_1[0][0] : (unsigned int)(int)(unsigned short)24315)) : ((_Bool)(signed char)14 ? 4294967272U : (unsigned int)(int)(unsigned char)3)) - 53); i_1 < (signed char)12; i_1 += (signed char)4) {
var_20 = (unsigned char)(_Bool)1;
for (unsigned long long int i_2 = ((unsigned long long int)~((int)(unsigned short)57503) - 18446744073709494112ULL); i_2 < 14ULL; i_2 += (102ULL - 98ULL)) {
for (unsigned short i_3 = (unsigned short)0; i_3 < ((int)var_16 - 61818); i_3 += ((int)195539258U - 45369)) {

var_21 = (i_0 % 2 == zero) ?
((signed char)( (_Bool)(~(-82 ? arr_6[i_0][i_2][i_0] : (unsigned long long int)44933859U)) ? max((unsigned long long int)((int)arr_5[i_1][i_2][i_0] << (arr_7[i_0][i_0][i_0] - 6247015860608722560ULL)), (1 ? 9846410982495393907LL : 11138240969048749202LL)) : ((unsigned long long int)(_Bool)min((unsigned long long int)-8523323934425105153LL, arr_4[i_0][i_0]) ? arr_1[i_2][i_0] : 161197919) )) :
((signed char)( (_Bool)(~(-82 ? arr_6[i_0][i_2][i_0] : (unsigned long long int)44933859U)) ? max((unsigned long long int)((int)arr_5[i_1][i_2][i_0] << (arr_7[i_0][i_0][i_0] - 6247015860608722560ULL - 16955323640971943331ULL)), (1 ? 9846410982495393907LL : 11138240969048749202LL)) : ((unsigned long long int)(_Bool)min((unsigned long long int)-8523323934425105153LL, arr_4[i_0][i_0]) ? arr_1[i_2][i_0] : 161197919) ));

for (_Bool i_4 = ((int)(_Bool)var_7 - 1); i_4 < (_Bool)1; i_4 += (int)(_Bool)(1 ? (int)(signed char)4 : (int)(unsigned short)57527)) {
if ((_Bool)max((unsigned long long int)((1 ? (unsigned long long int)4294967295U : 12ULL) <= (unsigned long long int)(15511 * 0)), ~arr_6[i_1][i_1][i_1])) {
} else {
var_33 = (signed char)( (_Bool)(12ULL ? (unsigned long long int)(int)(signed char)92 : 12860618151463637781ULL) ? ((unsigned long long int)(_Bool)arr_10[i_1][i_1 - 1] ? (unsigned int)102 : (1 ? 2184464458U : (unsigned int)(int)(signed char)12)) : ((_Bool)(_Bool)(unsigned short)42857 ? (int)(signed char)38 : (int)(signed char)-28) ? ((_Bool)(unsigned short)59866 ? arr_6[i_0][i_1][i_2] : (unsigned long long int)1) : (unsigned long long int)(int)!(_Bool)(short)19149 );
var_34 = (signed char)(+((_Bool)((_Bool)arr_9[i_0][i_0][i_0] ? arr_6[i_0][i_3][i_4] : (unsigned long long int)1) ? arr_2[i_0][i_1 + 1] : (unsigned long long int)((_Bool)arr_9[i_0][i_1][i_4] ? (unsigned int)(int)(_Bool)0 : 161197919)));
}
}
}
}
var_36 = (unsigned short)(~((_Bool)((_Bool)(signed char)-60 ? 516U : 195539258U) ? (1 * 102) : (502768189 % 2)));
}
}
}

int main() {
init();
test(arr_6, arr_7, arr_8, arr_9, arr_10);
checksum();
printf("%llu\n", seed);
return 0;
}
```

# Note the last several digits

```console
$ clang -w -mllvm -polly -O3 dri.c && ./a.out
46082543709636966

$ clang -w dri.c && ./a.out
46082543917544892

$ clang -w dri.c -fsanitize=undefined && ./a.out
46082543917544892
```

Attached preprocessed file: [dri-preproc.c](https://github.com/user-attachments/files/26817292/dri-preproc.c)

Contributor guide

Open the contributing guide

Research direction

Start by compiling dri.c with and without -mllvm -polly -O3, then compare the checksum output shown in the issue. Use the Godbolt reproducer and dri-preproc.c to isolate the Polly transformation responsible for the mismatch. Done means the miscompilation is explained and corrected, with both builds producing the expected checksum.

Written by the indexing model from the issue text.

Assessment

Tech stack
c
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.