SpirvShader: Implement SMod. Test: *smod* Bug: b/126873455 Change-Id: If946e72d23aa9386b85cffe96b02ab63195f0a24 Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/26549 Tested-by: Ben Clayton <bclayton@google.com> Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp index 228c01c..25ce989 100644 --- a/src/Pipeline/SpirvShader.cpp +++ b/src/Pipeline/SpirvShader.cpp
@@ -302,6 +302,7 @@ case spv::OpFUnordLessThanEqual: case spv::OpFOrdGreaterThanEqual: case spv::OpFUnordGreaterThanEqual: + case spv::OpSMod: case spv::OpUMod: case spv::OpIEqual: case spv::OpINotEqual: @@ -943,7 +944,7 @@ // TODO: what to do about zero-slot objects? if (pointeeTy.sizeInComponents > 0) { - routine->createLvalue(insn.word(2), pointeeTy.sizeInComponents); + routine->createLvalue(resultId, pointeeTy.sizeInComponents); } break; } @@ -1081,6 +1082,7 @@ case spv::OpFUnordLessThanEqual: case spv::OpFOrdGreaterThanEqual: case spv::OpFUnordGreaterThanEqual: + case spv::OpSMod: case spv::OpUMod: case spv::OpIEqual: case spv::OpINotEqual: @@ -1541,6 +1543,22 @@ case spv::OpUDiv: dst.emplace(i, As<SIMD::Float>(As<SIMD::UInt>(lhs) / As<SIMD::UInt>(rhs))); break; + case spv::OpSMod: + { + auto a = As<SIMD::Int>(lhs); + auto b = As<SIMD::Int>(rhs); + 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 + // that it is still congruent to a modulo b. + // + // See also http://mathforum.org/library/drmath/view/52343.html + auto signDiff = CmpNEQ(CmpGE(a, SIMD::Int(0)), CmpGE(b, SIMD::Int(0))); + auto fixedMod = mod + (b & CmpNEQ(mod, SIMD::Int(0)) & signDiff); + dst.emplace(i, As<SIMD::Float>(fixedMod)); + break; + } case spv::OpUMod: dst.emplace(i, As<SIMD::Float>(As<SIMD::UInt>(lhs) % As<SIMD::UInt>(rhs))); break;