From 1c154fff7156e3fcc46ed7cfdb17f8199287eaac Mon Sep 17 00:00:00 2001 From: Arvind Sudarsanam Date: Wed, 13 Sep 2023 12:57:33 -0400 Subject: [PATCH] Fix check for (neg) zero for fpclass emulation (#2154) We should compare not only to zero integer, but also 'negated' zero. --- lib/SPIRV/SPIRVWriter.cpp | 42 ++++++++++++++++++++++++++------- test/llvm-intrinsics/fpclass.ll | 26 +++++++++----------- 2 files changed, 45 insertions(+), 23 deletions(-) diff --git a/lib/SPIRV/SPIRVWriter.cpp b/lib/SPIRV/SPIRVWriter.cpp index 47edb65f3b..2212f043ef 100644 --- a/lib/SPIRV/SPIRVWriter.cpp +++ b/lib/SPIRV/SPIRVWriter.cpp @@ -4434,17 +4434,43 @@ SPIRVValue *LLVMToSPIRVBase::transIntrinsicInst(IntrinsicInst *II, if (FPClass & fcZero) { // Create zero integer constant and check for equality with bitcasted to // int float value + auto SetUpCMPToZero = [&](SPIRVValue *BitCastToInt, + bool IsPositive) -> SPIRVValue * { + APInt ZeroInt = APInt::getZero(BitSize); + if (IsPositive) { + auto *ZeroConst = + transValue(Constant::getIntegerValue(IntOpLLVMTy, ZeroInt), BB); + return BM->addCmpInst(OpIEqual, ResTy, BitCastToInt, ZeroConst, BB); + } + // Created 'negated' zero + ZeroInt.setSignBit(); + auto *NegZeroConst = + transValue(Constant::getIntegerValue(IntOpLLVMTy, ZeroInt), BB); + return BM->addCmpInst(OpIEqual, ResTy, BitCastToInt, NegZeroConst, BB); + }; auto *BitCastToInt = BM->addUnaryInst(OpBitcast, OpSPIRVTy, InputFloat, BB); - auto *ZeroConst = transValue( - Constant::getIntegerValue(IntOpLLVMTy, APInt::getZero(BitSize)), BB); - auto *TestIsZero = - BM->addCmpInst(OpIEqual, ResTy, BitCastToInt, ZeroConst, BB); - if (FPClass & fcPosZero && FPClass & fcNegZero) + if (FPClass & fcPosZero && FPClass & fcNegZero) { + APInt ZeroInt = APInt::getZero(BitSize); + auto *ZeroConst = + transValue(Constant::getIntegerValue(IntOpLLVMTy, ZeroInt), BB); + APInt MaskToClearSignBit = APInt::getSignedMaxValue(BitSize); + auto *MaskToClearSignBitConst = transValue( + Constant::getIntegerValue(IntOpLLVMTy, MaskToClearSignBit), BB); + auto *BitwiseAndRes = BM->addBinaryInst( + OpBitwiseAnd, OpSPIRVTy, BitCastToInt, MaskToClearSignBitConst, BB); + auto *TestIsZero = + BM->addCmpInst(OpIEqual, ResTy, BitwiseAndRes, ZeroConst, BB); ResultVec.emplace_back(GetInvertedTestIfNeeded(TestIsZero)); - else - ResultVec.emplace_back(GetInvertedTestIfNeeded( - GetNegPosInstTest(TestIsZero, FPClass & fcNegZero))); + } else if (FPClass & fcPosZero) { + auto *TestIsPosZero = + SetUpCMPToZero(BitCastToInt, true /*'positive' zero*/); + ResultVec.emplace_back(GetInvertedTestIfNeeded(TestIsPosZero)); + } else { + auto *TestIsNegZero = + SetUpCMPToZero(BitCastToInt, false /*'negated' zero*/); + ResultVec.emplace_back(GetInvertedTestIfNeeded(TestIsNegZero)); + } } if (ResultVec.size() == 1) return ResultVec.back(); diff --git a/test/llvm-intrinsics/fpclass.ll b/test/llvm-intrinsics/fpclass.ll index ef4ebedb9e..0b5c0345d0 100644 --- a/test/llvm-intrinsics/fpclass.ll +++ b/test/llvm-intrinsics/fpclass.ll @@ -21,6 +21,8 @@ ; CHECK-SPIRV-DAG: Constant [[#Int32Ty]] [[#QNanBitConst:]] 2143289344 ; CHECK-SPIRV-DAG: Constant [[#Int32Ty]] [[#MantissaConst:]] 8388607 ; CHECK-SPIRV-DAG: Constant [[#Int32Ty]] [[#ZeroConst:]] 0 +; CHECK-SPIRV-DAG: Constant [[#Int32Ty]] [[#MaskToClearSignBit:]] 2147483647 +; CHECK-SPIRV-DAG: Constant [[#Int32Ty]] [[#NegatedZeroConst:]] 2147483648 ; CHECK-SPIRV-DAG: Constant [[#Int64Ty]] [[#QNanBitConst64:]] 0 2146959360 ; CHECK-SPIRV-DAG: Constant [[#Int64Ty]] [[#MantissaConst64:]] 4294967295 1048575 ; CHECK-SPIRV-DAG: Constant [[#Int64Ty]] [[#ZeroConst64:]] 0 0 @@ -307,8 +309,9 @@ define i1 @test_class_zero(float %arg) { ; CHECK-SPIRV-EMPTY: ; CHECK-SPIRV-NEXT: Label ; CHECK-SPIRV-NEXT: Bitcast [[#Int32Ty]] [[#BitCast:]] [[#Val]] -; CHECK-SPIRV-NEXT: IEqual [[#BoolTy]] [[#Equal:]] [[#BitCast]] [[#ZeroConst]] -; CHECK-SPIRV-NEXT: ReturnValue [[#Equal]] +; CHECK-SPIRV-NEXT: BitwiseAnd [[#Int32Ty]] [[#BitwiseAndRes:]] [[#BitCast]] [[#MaskToClearSignBit]] +; CHECK-SPIRV-NEXT: IEqual [[#BoolTy]] [[#EqualPos:]] [[#BitwiseAndRes]] [[#ZeroConst]] +; CHECK-SPIRV-NEXT: ReturnValue [[#EqualPos]] %val = call i1 @llvm.is.fpclass.f32(float %arg, i32 96) ret i1 %val } @@ -320,11 +323,8 @@ define i1 @test_class_poszero(float %arg) { ; CHECK-SPIRV-EMPTY: ; CHECK-SPIRV-NEXT: Label ; CHECK-SPIRV-NEXT: Bitcast [[#Int32Ty]] [[#BitCast:]] [[#Val]] -; CHECK-SPIRV-NEXT: IEqual [[#BoolTy]] [[#Equal:]] [[#BitCast]] [[#ZeroConst]] -; CHECK-SPIRV-NEXT: SignBitSet [[#BoolTy]] [[#Sign:]] [[#Val]] -; CHECK-SPIRV-NEXT: LogicalNot [[#BoolTy]] [[#Not:]] [[#Sign]] -; CHECK-SPIRV-NEXT: LogicalAnd [[#BoolTy]] [[#And:]] [[#Not]] [[#Equal]] -; CHECK-SPIRV-NEXT: ReturnValue [[#And]] +; CHECK-SPIRV-NEXT: IEqual [[#BoolTy]] [[#Equal:]] [[#BitCast]] [[#ZeroConst]] +; CHECK-SPIRV-NEXT: ReturnValue [[#Equal]] %val = call i1 @llvm.is.fpclass.f32(float %arg, i32 64) ret i1 %val } @@ -336,10 +336,8 @@ define i1 @test_class_negzero(float %arg) { ; CHECK-SPIRV-EMPTY: ; CHECK-SPIRV-NEXT: Label ; CHECK-SPIRV-NEXT: Bitcast [[#Int32Ty]] [[#BitCast:]] [[#Val]] -; CHECK-SPIRV-NEXT: IEqual [[#BoolTy]] [[#Equal:]] [[#BitCast]] [[#ZeroConst]] -; CHECK-SPIRV-NEXT: SignBitSet [[#BoolTy]] [[#Sign:]] [[#Val]] -; CHECK-SPIRV-NEXT: LogicalAnd [[#BoolTy]] [[#And:]] [[#Sign]] [[#Equal]] -; CHECK-SPIRV-NEXT: ReturnValue [[#And]] +; CHECK-SPIRV-NEXT: IEqual [[#BoolTy]] [[#Equal:]] [[#BitCast]] [[#NegatedZeroConst]] +; CHECK-SPIRV-NEXT: ReturnValue [[#Equal]] %val = call i1 @llvm.is.fpclass.f32(float %arg, i32 32) ret i1 %val } @@ -383,11 +381,10 @@ define i1 @test_class_neginf_posnormal_negsubnormal_poszero_snan_f64(double %arg ; CHECK-SPIRV-NEXT: LogicalAnd [[#BoolTy]] [[#And4:]] [[#Sign]] [[#Less]] ; CHECK-SPIRV-NEXT: Bitcast [[#Int64Ty]] [[#BitCast3:]] [[#Val]] ; CHECK-SPIRV-NEXT: IEqual [[#BoolTy]] [[#Equal:]] [[#BitCast3]] [[#ZeroConst64]] -; CHECK-SPIRV-NEXT: LogicalAnd [[#BoolTy]] [[#And5:]] [[#Not2]] [[#Equal]] ; CHECK-SPIRV-NEXT: LogicalOr [[#BoolTy]] [[#Or1:]] [[#And1]] [[#And2]] ; CHECK-SPIRV-NEXT: LogicalOr [[#BoolTy]] [[#Or2:]] [[#Or1]] [[#And3]] ; CHECK-SPIRV-NEXT: LogicalOr [[#BoolTy]] [[#Or3:]] [[#Or2]] [[#And4]] -; CHECK-SPIRV-NEXT: LogicalOr [[#BoolTy]] [[#Or4:]] [[#Or3]] [[#And5]] +; CHECK-SPIRV-NEXT: LogicalOr [[#BoolTy]] [[#Or4:]] [[#Or3]] [[#Equal]] ; CHECK-SPIRV-NEXT: ReturnValue [[#Or4]] %val = call i1 @llvm.is.fpclass.f64(double %arg, i32 341) ret i1 %val @@ -416,11 +413,10 @@ define <2 x i1> @test_class_neginf_posnormal_negsubnormal_poszero_snan_v2f16(<2 ; CHECK-SPIRV-NEXT: LogicalAnd [[#VecBoolTy]] [[#And4:]] [[#Sign]] [[#Less]] ; CHECK-SPIRV-NEXT: Bitcast [[#Int16VecTy]] [[#BitCast3:]] [[#Val]] ; CHECK-SPIRV-NEXT: IEqual [[#VecBoolTy]] [[#Equal:]] [[#BitCast3]] [[#ZeroConst16]] -; CHECK-SPIRV-NEXT: LogicalAnd [[#VecBoolTy]] [[#And5:]] [[#Not2]] [[#Equal]] ; CHECK-SPIRV-NEXT: LogicalOr [[#VecBoolTy]] [[#Or1:]] [[#And1]] [[#And2]] ; CHECK-SPIRV-NEXT: LogicalOr [[#VecBoolTy]] [[#Or2:]] [[#Or1]] [[#And3]] ; CHECK-SPIRV-NEXT: LogicalOr [[#VecBoolTy]] [[#Or3:]] [[#Or2]] [[#And4]] -; CHECK-SPIRV-NEXT: LogicalOr [[#VecBoolTy]] [[#Or4:]] [[#Or3]] [[#And5]] +; CHECK-SPIRV-NEXT: LogicalOr [[#VecBoolTy]] [[#Or4:]] [[#Or3]] [[#Equal]] ; CHECK-SPIRV-NEXT: ReturnValue [[#Or4]] %val = call <2 x i1> @llvm.is.fpclass.v2f16(<2 x half> %arg, i32 341) ret <2 x i1> %val