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;
}

Empty file.
36 changes: 36 additions & 0 deletions tests/nostdlib/llvm_passes/Vectorize/ReturnVal/returnval.cpp
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)
Empty file.
55 changes: 55 additions & 0 deletions tests/nostdlib/llvm_passes/Vectorize/SLP/slp.cpp
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;
}

Empty file.
41 changes: 41 additions & 0 deletions tests/nostdlib/llvm_passes/Vectorize/SLPArgs/slpargs.cpp
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];
}

Empty file.
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);
}

Empty file.
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;
}

Empty file.
53 changes: 53 additions & 0 deletions tests/nostdlib/llvm_passes/Vectorize/Scalarize/scalarize.cpp
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];
}
Empty file.
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]));
}
Empty file.
52 changes: 52 additions & 0 deletions tests/nostdlib/llvm_passes/Vectorize/SpuriousVar/test.cpp
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);
}
51 changes: 51 additions & 0 deletions tests/nostdlib/llvm_passes/Vectorize/TempLoopVar/temploopvar.cpp
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);
}
Empty file.
Empty file.
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);
}