[llvm-bugs] [Bug 38697] New: Vectorization causes unsafe integer div-by-zero
via llvm-bugs
llvm-bugs at lists.llvm.org
Fri Aug 24 19:27:57 PDT 2018
https://bugs.llvm.org/show_bug.cgi?id=38697
Bug ID: 38697
Summary: Vectorization causes unsafe integer div-by-zero
Product: libraries
Version: trunk
Hardware: PC
OS: Windows NT
Status: NEW
Severity: normal
Priority: P
Component: Loop Optimizer
Assignee: unassignedbugs at nondot.org
Reporter: warren_ristow at playstation.sony.com
CC: llvm-bugs at lists.llvm.org
Created attachment 20766
--> https://bugs.llvm.org/attachment.cgi?id=20766&action=edit
test-case
The attached test-program is miscompiled when compiled with optimization
(eg -O2) when appropriate vector extensions are enabled (eg sse4.1). This
results in a run-time crash, due to an integer div-by-0. It's caused by what
appears to be a bug in vectorization.
For example, using a fairly modern trunk version:
$ clang --version
clang version 8.0.0 (trunk 340550)
Target: x86_64-unknown-linux-gnu
Thread model: posix
...
$ clang -O2 -msse4.1 -fno-vectorize -o testPass.elf test.c
$ clang -O2 -msse4.1 -o testFail.elf test.c
$ testPass.elf
{BEGIN}
{END}
$ testFail.elf
{BEGIN}
Floating point exception (core dumped)
$
I'm listing the program below, for ease of reference, to explain some
background.
The code contains a function 'test()':
int test(int val, int signedshift, int bits) { .... }
'test()' contains a loop, and that loop will be an infinite loop if 'bits' is 0
(and I think it is undefined behavior if 'bits' is less than 0). The caller
('main()', in this test-case) guards the call to 'test()', to only make the
call when that arg is known to be greater than 0. The caller has an outer
loop, and nested within it is a loop that's called when that arg is <= 0, and
a different loop that's called when the arg is > 0 (and this is the loop
that calls 'test()'). That is, 'main()' has the structure:
count = <expression>;
for (....) { // outer loop
if (count <= 0) {
for (....) { // first inner loop
// some code
}
} else {
for (....) { // second inner loop
// some other code
... test(v, shift, count); // loop in 'test()' gets vectorized
}
}
}
When vectorization is done on the loop in 'test()', an integer division that's
loop-invariant is created (the divisor is 'bits', which is 0 at run-time for
the case here). The function 'test()' is inlined into 'main()', and that
loop-invariant division is hoisted higher than it can safely be hoisted.
Specifically, it's hoisted to the pre-header of the outer loop of 'main()',
which causes a trap before entering the body of the outer loop (since 'count'
is 0). More details can be seen in the full code of "test.c", pasted below.
FTR, bisecting, I see this problem first appeared with r284939. However, I
think it's clear that that's a proper/correct change. Instead, it's just
exposing a problem in the vectorizer that was latent. Specifically, that
change is:
------------------------------------------------------------------------
r284939 | rksimon | 2016-10-23 09:49:04 -0700 (Sun, 23 Oct 2016) | 3 lines
Changed paths:
M /llvm/trunk/lib/Target/X86/X86TargetTransformInfo.cpp
M /llvm/trunk/test/Analysis/CostModel/X86/vshift-ashr-cost.ll
M /llvm/trunk/test/Analysis/CostModel/X86/vshift-lshr-cost.ll
M /llvm/trunk/test/Analysis/CostModel/X86/vshift-shl-cost.ll
[X86][SSE] Add SSE41/AVX1 costs for vector shifts.
We were defaulting to SSE2 costs which weren't taking into account the
availability of PBLENDW/PBLENDVB to improve merging of per-element shift
results.
------------------------------------------------------------------------
//////////////////////// test.c ////////////////////////
extern int printf(const char *, ...);
volatile int zero = 0; // volatile to suppress optimization
static int get_data() { return zero; } // some arbitrary data -- 0 works fine
unsigned char space[64];
int test(int val, int signedshift, int bits)
{
int result, tmp;
if (signedshift < 0) val <<= -signedshift;
else if (signedshift > 0) val >>= signedshift;
result = val;
tmp = bits;
// This loop is dead-code at run-time, but preventing vectorization of it
// suppresses the problem.
// #pragma clang loop vectorize(disable)
while (tmp < 8) {
result += val >> tmp;
tmp += bits;
}
return result;
}
int main()
{
// References to (volatile) 'zero' here to suppress constant propagation.
int xlim = 4 + zero;
int ylim = 1 + zero;
int shift = zero;
int count = zero;
int inx = 0;
printf("{BEGIN}\n");
for (int y = 0; y < ylim; ++y) {
if (count <= 0) { // At runtime, 'count' is 0, so we enter here.
for (int x = 0; x < xlim; ++x)
space[inx++] = (unsigned char) get_data();
} else { // At runtime, 'count' is 0, so this branch is dead.
for (int x = 0; x < xlim; ++x) {
int v = get_data();
space[inx++] = (unsigned char) test(v, shift, count);
}
}
}
printf("{END}\n");
return 0;
}
////////////////////////////////////////////////////////
--
You are receiving this mail because:
You are on the CC list for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-bugs/attachments/20180825/82f194bc/attachment-0001.html>
More information about the llvm-bugs
mailing list