| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| // RUN: %dexter | ||
| float foo[5]; | ||
|
|
||
| void | ||
| bar(float a1, float a2, float b1, float b2, float c1, float c2, float d1, float d2, float *A) | ||
| { | ||
| int tmp1 = 0; | ||
| tmp1 = a1*(a1 + b1)/b1; // DexExpectStepOrder(1) | ||
| tmp1 += 50*b1/a1; // DexExpectStepOrder(2) | ||
| A[0] = tmp1; // DexExpectStepOrder(3) | ||
| tmp1 = a2*(a2 + b2)/b2; // DexExpectStepOrder(4) | ||
| tmp1 += 50*b2/a2; // DexExpectStepOrder(5) | ||
| A[1] = tmp1; // DexExpectStepOrder(6) | ||
| if (a1 == 4) { // DexExpectStepOrder(7) | ||
| tmp1 = c1*(c1 + d1)/d1; // DexExpectStepOrder(8) | ||
| tmp1 += 50*d1/c1; // DexExpectStepOrder(9) | ||
| A[2] = tmp1; // DexExpectStepOrder(10) | ||
| } | ||
| tmp1 = c2*(c2 + d2)/d2; // DexExpectStepOrder(11) | ||
| tmp1 += 50*d2/c2; // DexExpectStepOrder(12) | ||
| A[3] = tmp1; // DexExpectStepOrder(13) | ||
| tmp1 = a2*(a2 + d2)/d2; // DexExpectStepOrder(14) | ||
| tmp1 += 50*d2/a2; // DexExpectStepOrder(15) | ||
| A[4] = tmp1; // DexExpectStepOrder(16) | ||
| } | ||
|
|
||
| int | ||
| main() { | ||
| volatile float a1, a2, b1, b2, c1, c2, d1, d2; | ||
| a1 = a2 = b1 = b2 = c1 = c2 = d1 = d2 = 4; | ||
|
|
||
| bar(a1, a2, b1, b2, c1, c2, d1, d2, foo); | ||
| return 0; | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| // RUN: %dexter | ||
| #include <string.h> | ||
|
|
||
| #define BUFSZ 32 | ||
|
|
||
| int | ||
| main() | ||
| { | ||
| int foo[BUFSZ]; | ||
| int bar[BUFSZ]; | ||
|
|
||
| memset(foo, 0, sizeof(foo)); | ||
| for (int i = 0; i < BUFSZ; i++) | ||
| bar[i] = 1; | ||
|
|
||
| for (int i = 0; i < BUFSZ; i++) | ||
| foo[i] += bar[i]; | ||
|
|
||
| int sum = 0; // DexWatch('sum') | ||
| for (int i = 0; i < BUFSZ; i++) // DexWatch('sum') | ||
| sum += foo[i]; // DexWatch('sum') | ||
|
|
||
| return sum; // DexWatch('sum') | ||
| } | ||
|
|
||
| // Tricky: these loops get vectorised, _and_ unrolled, to make zero loops. | ||
| // This is fine; however the value of 'sum' is not available at the end of | ||
| // the loop for some reason, _despite_ the fact it's in $rax, which is | ||
| // annoying | ||
| // | ||
| // Reported: https://bugs.llvm.org/show_bug.cgi?id=39019 | ||
|
|
||
| // DexExpectWatchValue('sum', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '30', '31', '32') | ||
| // DexExpectStepKind('FUNC', 1) | ||
| // In theory the memsets are external funcs, in practice they get localised | ||
| // DexExpectStepKind('FUNC_EXTERNAL', 0) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| // RUN: %dexter | ||
| float foo[4]; | ||
|
|
||
| void | ||
| bar(float a1, float a2, float b1, float b2, float c1, float c2, float d1, float d2, float *A) | ||
| { | ||
| int tmp1 = a1*(a1 + b1)/b1; // DexWatch('A', 'tmp1') | ||
| tmp1 += 50*b1/a1; // DexWatch('A', 'tmp1') | ||
| A[0] = tmp1; // DexWatch('A', 'tmp1') | ||
| int tmp2 = a2*(a2 + b2)/b2; // DexWatch('A', 'tmp1', 'tmp2') | ||
| tmp2 += 50*b2/a2; // DexWatch('A', 'tmp1', 'tmp2') | ||
| A[1] = tmp2; // DexWatch('A', 'tmp1', 'tmp2') | ||
| int tmp3 = c1*(c1 + d1)/d1; // DexWatch('A', 'tmp1', 'tmp2', 'tmp3') | ||
| tmp3 += 50*d1/c1; // DexWatch('A', 'tmp1', 'tmp2', 'tmp3') | ||
| A[2] = tmp3; // DexWatch('A', 'tmp1', 'tmp2', 'tmp3') | ||
| int tmp4 = c2*(c2 + d2)/d2; // DexWatch('A', 'tmp1', 'tmp2', 'tmp3', 'tmp4') | ||
| tmp4 += 50*d2/c2; // DexWatch('A', 'tmp1', 'tmp2', 'tmp3', 'tmp4') | ||
| A[3] = tmp4; // DexWatch('A', 'tmp1', 'tmp2', 'tmp3', 'tmp4') | ||
| } | ||
|
|
||
| // Check that when SLP vectorized, the designated variables are unreadable. | ||
| // There's no expect-value checker, thus any value read is reported as an error | ||
| // (I think) | ||
|
|
||
| void | ||
| baz(float a1, float a2, float b1, float b2, float c1, float c2, float d1, float d2, float *A) | ||
| { | ||
| int tmp1 = a1*(a1 + b1)/b1; | ||
| tmp1 += 50*b1/a1; | ||
| A[0] = tmp1; | ||
| int tmp2 = a2*(a2 + b2)/b2; // DexUnreachable() | ||
| tmp2 += 50*b2/a2; // DexUnreachable() | ||
| A[1] = tmp2; // DexUnreachable() | ||
| int tmp3 = c1*(c1 + d1)/d1; // DexUnreachable() | ||
| tmp3 += 50*d1/c1; // DexUnreachable() | ||
| A[2] = tmp3; // DexUnreachable() | ||
| int tmp4 = c2*(c2 + d2)/d2; // DexUnreachable() | ||
| tmp4 += 50*d2/c2; // DexUnreachable() | ||
| A[3] = tmp4; // DexUnreachable() | ||
| } | ||
| // Check that when SLP vectorized, we don't step through random bits of the | ||
| // vectorized function. This *might* be fragile wrt. where the vectorizer | ||
| // picks its DebugLocs from, but it's not clear whether that's liable to change | ||
|
|
||
|
|
||
| int | ||
| main() { | ||
| volatile float a1, a2, b1, b2, c1, c2, d1, d2; | ||
| a1 = a2 = b1 = b2 = c1 = c2 = d1 = d2 = 4; | ||
|
|
||
| bar(a1, a2, b1, b2, c1, c2, d1, d2, foo); | ||
| baz(a1, a2, b1, b2, c1, c2, d1, d2, foo); | ||
| return 0; | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| // RUN: %dexter | ||
| float foo[4]; | ||
|
|
||
| // Ensure that all arguments are readable after their usages are vectorized. | ||
| // Killing off args because their values are optimized would sucks. | ||
|
|
||
| void | ||
| bar(float a1, float a2, float b1, float b2, float c1, float c2, float d1, float d2, float *A) | ||
| { | ||
| int tmp1 = a1*(a1 + b1)/b1; // DexWatch('a1', 'a2', 'b1', 'b2', 'c1', 'c2', 'd1', 'd2', 'A') | ||
| tmp1 += 50*b1/a1; | ||
| A[0] = tmp1; | ||
| int tmp2 = a2*(a2 + b2)/b2; | ||
| tmp2 += 50*b2/a2; | ||
| A[1] = tmp2; | ||
| int tmp3 = c1*(c1 + d1)/d1; | ||
| tmp3 += 50*d1/c1; | ||
| A[2] = tmp3; | ||
| int tmp4 = c2*(c2 + d2)/d2; | ||
| tmp4 += 50*d2/c2; | ||
| A[3] = tmp4; | ||
| } | ||
|
|
||
| // DexExpectWatchValue('a1', '4') | ||
| // DexExpectWatchValue('a2', '4') | ||
| // DexExpectWatchValue('b1', '4') | ||
| // DexExpectWatchValue('b2', '4') | ||
| // DexExpectWatchValue('c1', '4') | ||
| // DexExpectWatchValue('c2', '4') | ||
| // DexExpectWatchValue('d1', '4') | ||
| // DexExpectWatchValue('d2', '4') | ||
|
|
||
| int | ||
| main() { | ||
| volatile float a1, a2, b1, b2, c1, c2, d1, d2; | ||
| a1 = a2 = b1 = b2 = c1 = c2 = d1 = d2 = 4; | ||
|
|
||
| bar(a1, a2, b1, b2, c1, c2, d1, d2, foo); | ||
| return foo[0]; | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| // RUN: %dexter | ||
| float foo[5]; | ||
|
|
||
| int | ||
| bar(float a1, float a2, float b1, float b2, float c1, float c2, float d1, float d2, float *A) | ||
| { | ||
| int tmp1 = 0, tmp2; // This huge block gets SLP vectorized, | ||
| tmp1 = a1*(a1 + b1)/b1; | ||
| tmp1 += 50*b1/a1; | ||
| A[0] = tmp1; | ||
| tmp1 = a2*(a2 + b2)/b2; | ||
| tmp1 += 50*b2/a2; | ||
| A[1] = tmp1; | ||
| tmp2 = c1*(c1 + d1)/d1; | ||
| tmp2 += 50*d1/c1; | ||
| A[2] = tmp2; | ||
| tmp1 = c2*(c2 + d2)/d2; | ||
| tmp1 += 50*d2/c2; | ||
| A[3] = tmp1; | ||
| // From here, the code is scalar, and the tmp2 addition is an integer in | ||
| // normal x86 registers. But because tmp2 comes from an slp vectorized | ||
| // section of code, it doesn't get at dbg.value. | ||
| tmp1 = a2*(a2 + d2)/d2; | ||
| tmp1 += tmp2; // DexWatch('tmp1', 'tmp2') | ||
| tmp1 += 50*d2/a2; // DexWatch('tmp1', 'tmp2') | ||
| A[4] = tmp1; // DexWatch('tmp1', 'tmp2') | ||
| return tmp2; // DexWatch('tmp1', 'tmp2') | ||
| // DexExpectWatchValue('tmp1', '8', '66', '116') | ||
| // DexExpectWatchValue('tmp2', '58') | ||
| } | ||
|
|
||
| int | ||
| main() { | ||
| volatile float a1, a2, b1, b2, c1, c2, d1, d2; | ||
| a1 = a2 = b1 = b2 = c1 = c2 = d1 = d2 = 4; | ||
|
|
||
| return bar(a1, a2, b1, b2, c1, c2, d1, d2, foo); | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| // RUN: %dexter | ||
| float foo[5]; | ||
|
|
||
| void | ||
| bar(float a1, float a2, float b1, float b2, float c1, float c2, float d1, float d2, float *A) | ||
| { | ||
| int tmp1 = 0; | ||
| tmp1 = a1*(a1 + b1)/b1; | ||
| tmp1 += 50*b1/a1; | ||
| A[0] = tmp1; | ||
| tmp1 = a2*(a2 + b2)/b2; | ||
| tmp1 += 50*b2/a2; | ||
| A[1] = tmp1; | ||
| tmp1 = c1*(c1 + d1)/d1; | ||
| tmp1 += 50*d1/c1; | ||
| A[2] = tmp1; | ||
| tmp1 = c2*(c2 + d2)/d2; | ||
| tmp1 += 50*d2/c2; | ||
| A[3] = tmp1; | ||
| tmp1 = a2*(a2 + d2)/d2; // DexWatch('a2', 'd2') | ||
| tmp1 += 50*d2/a2; // DexWatch('tmp1', 'a2', 'd2') | ||
| A[4] = tmp1; // DexWatch('tmp1') | ||
| } | ||
|
|
||
| // Scalar tail of this loop should be visible | ||
| // DexExpectWatchValue('a2', '4') | ||
| // DexExpectWatchValue('d2', '4') | ||
| // DexExpectWatchValue('tmp1', '8', '58') | ||
|
|
||
| int | ||
| main() { | ||
| volatile float a1, a2, b1, b2, c1, c2, d1, d2; | ||
| a1 = a2 = b1 = b2 = c1 = c2 = d1 = d2 = 4; | ||
|
|
||
| bar(a1, a2, b1, b2, c1, c2, d1, d2, foo); | ||
| return 0; | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| // RUN: %dexter | ||
| #include <stdlib.h> | ||
| #include <string.h> | ||
|
|
||
| #define BUFSZ 16 | ||
|
|
||
| void | ||
| xyzzy(int ** out, int len) | ||
| { | ||
| #pragma clang loop vectorize(enable) vectorize_width(4) interleave_count(1) | ||
| for (int i = 0; i < len; i++) { // DexWatch('len') | ||
| int tmp = i; | ||
| tmp += len; // DexWatch('len', 'tmp') | ||
| tmp += 12; // DexWatch('len', 'tmp') | ||
| *out[i] = tmp; // DexWatch('len', 'tmp') | ||
| } | ||
| // Gratuitously vectorize a loop and then scalarize it's writeback, just to | ||
| // see if 'tmp' gets values reported. (It doesn't). 'i' is currently constant | ||
| // zero on account of other bugs. | ||
| // DexExpectWatchValue('len', '16') | ||
| // No watch value for tmp -> max penalty if a value is seen. | ||
| } | ||
|
|
||
| void | ||
| xyzzy2(int ** out, int len) | ||
| { | ||
| #pragma clang loop vectorize(enable) vectorize_width(4) interleave_count(1) | ||
| for (int i = 0; i < len; i++) { // DexExpectStepOrder(1, 4, 7, 10) | ||
| int tmp = i; | ||
| tmp += len; | ||
| tmp += 12; // DexExpectStepOrder(2, 5, 8, 11) | ||
| *out[i] = tmp; // DexExpectStepOrder(3, 6, 9, 12) | ||
| } | ||
| // Gratuitously vectorize a loop and check stepping: the writebacks to out | ||
| // are (excellently) all in one block, but there's then a jump back to | ||
| // '+= 12' where it would appear the induction-incrementing of 'i' in a vector | ||
| // register gets the wrong line no? Either way, generates a spurious step. | ||
| } | ||
|
|
||
| int | ||
| main() | ||
| { | ||
| int baz[BUFSZ]; | ||
| int *qux[BUFSZ]; | ||
|
|
||
| for (int i = 0; i < BUFSZ; i++) { | ||
| qux[i] = &baz[i]; | ||
| } | ||
|
|
||
| xyzzy(qux, BUFSZ); | ||
| xyzzy2(qux, BUFSZ); | ||
| return baz[0]; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| // RUN: %dexter | ||
| #include <stdlib.h> | ||
| #include <string.h> | ||
|
|
||
| #define BUFSZ 256 | ||
|
|
||
| int | ||
| foo(int argc) | ||
| { | ||
| int foo[BUFSZ]; | ||
| int bar[BUFSZ]; | ||
|
|
||
| if (argc + 1 > BUFSZ) | ||
| return 0; | ||
|
|
||
| // So: when fed '8' as the loop size (argc), we step in and out of the loop | ||
| // below three times, but only on 'bar[j] += argc' once. It's a pain if | ||
| // you have an expectation about the loop having the same body on each | ||
| // iteration of the loop; and in fact, this _does_ exercise the same (VF=4 | ||
| // UF=2) body each time. It's just that the surrounding plumbing encodes | ||
| // a few steps through the loop of its own account. | ||
| // If you run with argc==10, you get each flavour of the loop, the first line | ||
| // by itself, then both, then only the last line. | ||
| // This test just doesn't work well in -O0 | ||
|
|
||
| memset(foo, 0, sizeof(foo)); | ||
| for (int j = 0; j < argc; j++) { // DexExpectStepOrder(1, 4, 7) | ||
| bar[j] = 1; // DexExpectStepOrder(2, 5, 8) | ||
| bar[j] += argc; // DexExpectStepOrder(3, 5, 9) | ||
| } | ||
|
|
||
| for (int i = 0; i < argc; i++) | ||
| foo[i] += bar[i]; | ||
|
|
||
| int sum = 0; | ||
| for (int i = 0; i < argc; i++) | ||
| sum += foo[i]; | ||
|
|
||
| return sum; | ||
| } | ||
|
|
||
| #include <stdlib.h> | ||
|
|
||
| int foo(int argc); | ||
|
|
||
| int | ||
| main(int argc, char **argv) | ||
| { | ||
| if (argc == 1) | ||
| return foo(8); | ||
| else | ||
| return foo(atoi(argv[1])); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| // In this file, the 'bees' variables first assignment in the loop gets | ||
| // hoisted out, and the rest of the pipeline decides that it's live across | ||
| // the vectorized loop. This leads to the _good_ debug feature of the variable | ||
| // having a location on the line using the hoisted value (which would | ||
| // otherwise be unavailable), but the bad debug feature of it being the wrong | ||
| // value for the rest of the loop. | ||
| // The actual bug here is a repeat of LLVM PR39018 | ||
| #include <stdlib.h> | ||
| #include <string.h> | ||
| #include <stdlib.h> | ||
|
|
||
| #define BUFSZ 256 | ||
|
|
||
| int | ||
| foo(int argc, int init) | ||
| { | ||
| int foo[BUFSZ]; | ||
| int bar[BUFSZ]; | ||
|
|
||
| if (argc + 1 > BUFSZ) | ||
| return 0; | ||
|
|
||
| memset(foo, 0, sizeof(foo)); | ||
| memset(bar, 0, sizeof(bar)); | ||
| int tmp = argc; | ||
| int bees = 0; | ||
| for (int j = 0; j < argc; j++) { | ||
| bees = tmp + init; | ||
| bees += bar[j]; | ||
| if (j & 1) | ||
| bees += 1; | ||
| bar[j] = bees; | ||
| } | ||
|
|
||
| for (int i = 0; i < argc; i++) | ||
| foo[i] += bar[i]; | ||
|
|
||
| int sum = 0; | ||
| for (int i = 0; i < argc; i++) | ||
| sum += foo[i]; | ||
|
|
||
| return sum; | ||
| } | ||
|
|
||
| int | ||
| main(int argc, char **argv) | ||
| { | ||
| if (argc == 1) | ||
| return foo(8, 1); | ||
| else | ||
| return foo(atoi(argv[1]), 1); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| // RUN: %dexter | ||
| #include <stdlib.h> | ||
| #include <string.h> | ||
|
|
||
| #define BUFSZ 256 | ||
|
|
||
| int | ||
| foo(int argc, int init) | ||
| { | ||
| int foo[BUFSZ]; | ||
| int bar[BUFSZ]; | ||
|
|
||
| if (argc + 1 > BUFSZ) | ||
| return 0; | ||
|
|
||
| memset(foo, 0, sizeof(foo)); | ||
| int tmp = 12; | ||
| for (int j = 0; j < argc; j++) { // DexWatch('tmp') | ||
| tmp = init; // DexUnreachable() | ||
| tmp += argc; // DexUnreachable() | ||
| bar[j] = tmp;// DexWatch('tmp') | ||
| } | ||
|
|
||
| // DexExpectWatchValue('tmp', '12', '75') | ||
| // Tmp gets hoisted; check that this behaviour doesn't change. Mark | ||
| // intermediate lines as unreachable -- if they become reachable, this test | ||
| // needs to change. | ||
| // Really doesn't work with O0. | ||
|
|
||
| for (int i = 0; i < argc; i++) | ||
| foo[i] += bar[i]; | ||
|
|
||
| int sum = 0; | ||
| for (int i = 0; i < argc; i++) | ||
| sum += foo[i]; | ||
|
|
||
| return sum; | ||
| } | ||
|
|
||
| #include <stdlib.h> | ||
|
|
||
| int foo(int argc, int init); | ||
|
|
||
| int | ||
| main(int argc, char **argv) | ||
| { | ||
| if (argc == 1) | ||
| return foo(74, 1); // 64 + 8 + 2 = round each unrolling of vectorization | ||
| else | ||
| return foo(atoi(argv[1]), 1); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| // RUN: %dexter | ||
| #include <stdlib.h> | ||
| #include <string.h> | ||
|
|
||
| #define BUFSZ 256 | ||
|
|
||
| int | ||
| foo(int argc, int init) | ||
| { | ||
| int foo[BUFSZ]; | ||
| int bar[BUFSZ]; | ||
|
|
||
| if (argc + 1 > BUFSZ) | ||
| return 0; | ||
|
|
||
| memset(foo, 0, sizeof(foo)); | ||
| int tmp; | ||
| for (int j = 0; j < argc; j++) {// DexExpectStepOrder(1, 4, 7, 10, 13, 16, 19) | ||
| tmp = init; | ||
| tmp += j; // DexExpectStepOrder(2, 5, 8, 11, 14, 17, 20) | ||
| bar[j] = tmp; // DexExpectStepOrder(3, 6, 9, 12, 15, 18, 21) | ||
| } | ||
|
|
||
| // Soooooo, this is another test where the line numbers bounce around quite | ||
| // a bit in the VF=4 UF=16(?) loop. Instruction-level-parallelism may be | ||
| // coming into play, but it's still freaky. | ||
|
|
||
| for (int i = 0; i < argc; i++) | ||
| foo[i] += bar[i]; | ||
|
|
||
| int sum = 0; | ||
| for (int i = 0; i < argc; i++) | ||
| sum += foo[i]; | ||
|
|
||
| return sum; | ||
| } | ||
|
|
||
| #include <stdlib.h> | ||
|
|
||
| int foo(int argc, int init); | ||
|
|
||
| int | ||
| main(int argc, char **argv) | ||
| { | ||
| if (argc == 1) | ||
| return foo(74, 1); | ||
| else | ||
| return foo(atoi(argv[1]), 1); | ||
| } |