OSDN Git Service

Reactor: Fix add/sub sat generic code generation
authorLogan Chien <loganchien@google.com>
Wed, 26 Sep 2018 10:58:03 +0000 (18:58 +0800)
committerChris Forbes <chrisforbes@google.com>
Thu, 27 Sep 2018 16:15:40 +0000 (16:15 +0000)
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>
src/Reactor/LLVMReactor.cpp

index dd09cf7..6bc889e 100644 (file)
@@ -180,32 +180,58 @@ namespace
        }
 
        // 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)