Fix unsigned "less than zero" comparison
From the SPIR-V spec:
OpSMod's result is the remainder r of Operand 1 divided by Operand 2
where if r != 0, the sign of r is the same as the sign of Operand 2.
The less than comparison here was trying to correct the cases where C's
modulo had a different sign than SPIR-V's modulo. We can solve this by
directly comparing the sign of the C modulo against Operand 2's sign.
Bug chromium:973848
Change-Id: I27c88b7aaed35db5ba4df2cc0aac6061098f32c4
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/32868
Tested-by: Sean Risser <srisser@google.com>
Presubmit-Ready: Sean Risser <srisser@google.com>
Reviewed-by: Alexis Hétu <sugoi@google.com>
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp
index 05e1623..4a8c890 100644
--- a/src/Pipeline/SpirvShader.cpp
+++ b/src/Pipeline/SpirvShader.cpp
@@ -6103,10 +6103,10 @@
case spv::OpSMod:
if (r == 0) r = UINT32_MAX;
if (l == static_cast<uint32_t>(INT32_MIN)) l = UINT32_MAX;
- if (l * r < 0)
- v = static_cast<int32_t>(l) % static_cast<int32_t>(r) + r;
- else
- v = static_cast<int32_t>(l) % static_cast<int32_t>(r);
+ // Test if a signed-multiply would be negative.
+ v = static_cast<int32_t>(l) % static_cast<int32_t>(r);
+ if ((v & 0x80000000) != (r & 0x80000000))
+ v += r;
break;
case spv::OpShiftRightLogical:
v = l >> r;