OSDN Git Service

SpirvShader: Fix for integer overflow in SDiv and SMod.
authorBen Clayton <bclayton@google.com>
Thu, 14 Mar 2019 19:32:41 +0000 (19:32 +0000)
committerBen Clayton <bclayton@google.com>
Thu, 14 Mar 2019 20:07:45 +0000 (20:07 +0000)
See b/128614198 for context.

Tests: dEQP-VK.glsl.operator.binary_operator.div.*ivec*
Tests: dEQP-VK.glsl.operator.binary_operator.mod.*ivec*
Bug: b/128614198
Change-Id: I3c517a18ce003466b1ba382f1896b356e543f5d5
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/27248
Presubmit-Ready: Ben Clayton <bclayton@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Reviewed-by: Chris Forbes <chrisforbes@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Tested-by: Ben Clayton <bclayton@google.com>
src/Pipeline/SpirvShader.cpp

index 2ebb30a..24fb2da 100644 (file)
@@ -1538,8 +1538,11 @@ namespace sw
                                break;
                        case spv::OpSDiv:
                        {
-                               auto zeroMask = CmpEQ(rhs.Int(i), SIMD::Int(0));
-                               dst.emplace(i, lhs.Int(i) / (rhs.Int(i) | zeroMask));
+                               SIMD::Int a = lhs.Int(i);
+                               SIMD::Int b = rhs.Int(i);
+                               b = b | CmpEQ(b, SIMD::Int(0)); // prevent divide-by-zero
+                               a = a | (CmpEQ(a, SIMD::Int(0x80000000)) & CmpEQ(b, SIMD::Int(-1))); // prevent integer overflow
+                               dst.emplace(i, a / b);
                                break;
                        }
                        case spv::OpUDiv:
@@ -1550,10 +1553,11 @@ namespace sw
                        }
                        case spv::OpSMod:
                        {
-                               auto a = lhs.Int(i);
-                               auto b = rhs.Int(i);
-                               auto zeroMask = CmpEQ(b, SIMD::Int(0));
-                               auto mod = a % (b | zeroMask);
+                               SIMD::Int a = lhs.Int(i);
+                               SIMD::Int b = rhs.Int(i);
+                               b = b | CmpEQ(b, SIMD::Int(0)); // prevent divide-by-zero
+                               a = a | (CmpEQ(a, SIMD::Int(0x80000000)) & CmpEQ(b, SIMD::Int(-1))); // prevent integer overflow
+                               auto mod = a % b;
                                // If a and b have opposite signs, the remainder operation takes
                                // the sign from a but OpSMod is supposed to take the sign of b.
                                // Adding b will ensure that the result has the correct sign and