Reactor: Fix add/sub sat generic code generation
This commit fixes saturated add/sub instructions in generic LLVM code
generation path.
Bug: b/115344057
Test: dEQP-GLES3.functional.texture.wrap.rgba8
Change-Id: Ie3e3b708565b3ad255804090e8a3ee5521f42982
Reviewed-on: https://swiftshader-review.googlesource.com/20928
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Reviewed-by: Chris Forbes <chrisforbes@google.com>
Tested-by: Chris Forbes <chrisforbes@google.com>
diff --git a/src/Reactor/LLVMReactor.cpp b/src/Reactor/LLVMReactor.cpp
index dd09cf7..6bc889e 100644
--- a/src/Reactor/LLVMReactor.cpp
+++ b/src/Reactor/LLVMReactor.cpp
@@ -180,32 +180,58 @@
}
// Packed add/sub saturatation
- llvm::Value *lowerPSAT(llvm::Intrinsic::ID intrinsic, llvm::Value *x, llvm::Value *y)
+ llvm::Value *lowerPSAT(llvm::Value *x, llvm::Value *y, bool isAdd, bool isSigned)
{
- llvm::Function *func = llvm::Intrinsic::getDeclaration(
- ::module, intrinsic, {x->getType(), y->getType()});
- llvm::Value *ret = ::builder->CreateCall(func, ARGS(x, y));
- return ::builder->CreateExtractValue(ret, {0});
+ llvm::VectorType *ty = llvm::cast<llvm::VectorType>(x->getType());
+ llvm::VectorType *extTy = llvm::VectorType::getExtendedElementVectorType(ty);
+
+ unsigned numBits = ty->getScalarSizeInBits();
+
+ llvm::Value *max, *min, *extX, *extY;
+ if (isSigned)
+ {
+ max = llvm::ConstantInt::get(extTy, (1LL << (numBits - 1)) - 1, true);
+ min = llvm::ConstantInt::get(extTy, (-1LL << (numBits - 1)), true);
+ extX = ::builder->CreateSExt(x, extTy);
+ extY = ::builder->CreateSExt(y, extTy);
+ }
+ else
+ {
+ assert(numBits <= 64);
+ uint64_t maxVal = (numBits == 64) ? ~0ULL : (1ULL << numBits) - 1;
+ max = llvm::ConstantInt::get(extTy, maxVal, false);
+ min = llvm::ConstantInt::get(extTy, 0, false);
+ extX = ::builder->CreateZExt(x, extTy);
+ extY = ::builder->CreateZExt(y, extTy);
+ }
+
+ llvm::Value *res = isAdd ? ::builder->CreateAdd(extX, extY)
+ : ::builder->CreateSub(extX, extY);
+
+ res = lowerPMINMAX(res, min, llvm::ICmpInst::ICMP_SGT);
+ res = lowerPMINMAX(res, max, llvm::ICmpInst::ICMP_SLT);
+
+ return ::builder->CreateTrunc(res, ty);
}
llvm::Value *lowerPUADDSAT(llvm::Value *x, llvm::Value *y)
{
- return lowerPSAT(llvm::Intrinsic::uadd_with_overflow, x, y);
+ return lowerPSAT(x, y, true, false);
}
llvm::Value *lowerPSADDSAT(llvm::Value *x, llvm::Value *y)
{
- return lowerPSAT(llvm::Intrinsic::sadd_with_overflow, x, y);
+ return lowerPSAT(x, y, true, true);
}
llvm::Value *lowerPUSUBSAT(llvm::Value *x, llvm::Value *y)
{
- return lowerPSAT(llvm::Intrinsic::usub_with_overflow, x, y);
+ return lowerPSAT(x, y, false, false);
}
llvm::Value *lowerPSSUBSAT(llvm::Value *x, llvm::Value *y)
{
- return lowerPSAT(llvm::Intrinsic::ssub_with_overflow, x, y);
+ return lowerPSAT(x, y, false, true);
}
llvm::Value *lowerSQRT(llvm::Value *x)