https://github.com/danbrown-amd updated https://github.com/llvm/llvm-project/pull/225947
>From daaa5fc7c10c50e891f013abd998af8173a92861 Mon Sep 17 00:00:00 2001 From: Dan Brown <[email protected]> Date: Thu, 21 May 2026 16:04:07 -0600 Subject: [PATCH] Implements isfinite() HLSL intrinsic. Resolves #99131 Assisted-by: Claude Sonnet 4 --- clang/include/clang/Basic/Builtins.td | 6 ++ clang/include/clang/Basic/HLSLIntrinsics.td | 15 +++++ clang/lib/CodeGen/CGHLSLBuiltins.cpp | 19 ++++++ clang/lib/CodeGen/CGHLSLRuntime.h | 1 + .../lib/Headers/hlsl/hlsl_compat_overloads.h | 13 ++++ clang/lib/Sema/SemaHLSL.cpp | 1 + .../builtins/isfinite-overloads.hlsl | 37 +++++++++++ clang/test/CodeGenHLSL/builtins/isfinite.hlsl | 62 +++++++++++++++++++ .../SemaHLSL/BuiltIns/isfinite-errors.hlsl | 27 ++++++++ llvm/include/llvm/IR/IntrinsicsDirectX.td | 2 + llvm/lib/Target/DirectX/DXIL.td | 1 + .../Target/DirectX/DXILIntrinsicExpansion.cpp | 4 ++ .../DirectX/DirectXTargetTransformInfo.cpp | 1 + .../Target/SPIRV/SPIRVInstructionSelector.cpp | 33 +++++++++- .../CodeGen/DirectX/LongVector/isfinite.ll | 11 ++++ llvm/test/CodeGen/DirectX/isfinite.ll | 62 +++++++++++++++++++ llvm/test/CodeGen/DirectX/isfinite_error.ll | 14 +++++ .../SPIRV/hlsl-intrinsics/OpIsFinite.ll | 20 ++++-- 18 files changed, 322 insertions(+), 7 deletions(-) create mode 100644 clang/test/CodeGenHLSL/builtins/isfinite-overloads.hlsl create mode 100644 clang/test/CodeGenHLSL/builtins/isfinite.hlsl create mode 100644 clang/test/SemaHLSL/BuiltIns/isfinite-errors.hlsl create mode 100644 llvm/test/CodeGen/DirectX/LongVector/isfinite.ll create mode 100644 llvm/test/CodeGen/DirectX/isfinite.ll create mode 100644 llvm/test/CodeGen/DirectX/isfinite_error.ll diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 28178c0370b27..4d6bf60813e0e 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -5756,6 +5756,12 @@ def HLSLFrac : LangBuiltin<"HLSL_LANG"> { let Prototype = "void(...)"; } +def HLSLIsfinite : LangBuiltin<"HLSL_LANG"> { + let Spellings = ["__builtin_hlsl_elementwise_isfinite"]; + let Attributes = [NoThrow, Const]; + let Prototype = "void(...)"; +} + def HLSLIsinf : LangBuiltin<"HLSL_LANG"> { let Spellings = ["__builtin_hlsl_elementwise_isinf"]; let Attributes = [NoThrow, Const, CustomTypeChecking]; diff --git a/clang/include/clang/Basic/HLSLIntrinsics.td b/clang/include/clang/Basic/HLSLIntrinsics.td index 10adf4fb676ee..6369def55f2c7 100644 --- a/clang/include/clang/Basic/HLSLIntrinsics.td +++ b/clang/include/clang/Basic/HLSLIntrinsics.td @@ -1085,6 +1085,21 @@ call. let IsConvergent = 1; } +// Determines if the specified value x is finite. +def hlsl_isfinite : HLSLOneArgBuiltin<"isfinite", "__builtin_hlsl_elementwise_isfinite"> { + let Doc = [{ +\fn T isinf(T x) +\brief Determines if the specified value \a x is finite. +\param x The specified input value. + +Returns a value of the same size as the input, with a value set +to False if the x parameter is +INF, -INF, NaN, or QNaN. Otherwise, True. +}]; + let ReturnType = VaryingShape<BoolTy>; + let VaryingTypes = [HalfTy, FloatTy]; + let VaryingLongVector = 1; +} + // Determines if the specified value x is infinite. def hlsl_isinf : HLSLOneArgBuiltin<"isinf", "__builtin_hlsl_elementwise_isinf"> { let Doc = [{ diff --git a/clang/lib/CodeGen/CGHLSLBuiltins.cpp b/clang/lib/CodeGen/CGHLSLBuiltins.cpp index 26220e3a732bf..57742a75fac5d 100644 --- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp +++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp @@ -1225,6 +1225,25 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, /*ReturnType=*/Op0->getType(), CGM.getHLSLRuntime().getFracIntrinsic(), ArrayRef<Value *>{Op0}, nullptr, "hlsl.frac"); } + case Builtin::BI__builtin_hlsl_elementwise_isfinite: { + Value *Op0 = EmitScalarExpr(E->getArg(0)); + llvm::Type *Xty = Op0->getType(); + llvm::Type *retType = llvm::Type::getInt1Ty(this->getLLVMContext()); + if (Xty->isVectorTy()) { + unsigned NumElts; + if (auto *MatTy = E->getArg(0)->getType()->getAs<ConstantMatrixType>()) + NumElts = MatTy->getNumRows() * MatTy->getNumColumns(); + else + NumElts = + E->getArg(0)->getType()->castAs<VectorType>()->getNumElements(); + retType = llvm::VectorType::get(retType, ElementCount::getFixed(NumElts)); + } + if (!E->getArg(0)->getType()->hasFloatingRepresentation()) + llvm_unreachable("isfinite operand must have a float representation"); + return Builder.CreateIntrinsic( + retType, CGM.getHLSLRuntime().getIsFiniteIntrinsic(), + ArrayRef<Value *>{Op0}, nullptr, "hlsl.isfinite"); + } case Builtin::BI__builtin_hlsl_elementwise_isinf: { Value *Op0 = EmitScalarExpr(E->getArg(0)); if (!E->getArg(0)->getType()->hasFloatingRepresentation()) diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h index c44fb102598b0..d876d76d877d2 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -127,6 +127,7 @@ class CGHLSLRuntime { GENERATE_HLSL_INTRINSIC_FUNCTION(Frac, frac) GENERATE_HLSL_INTRINSIC_FUNCTION(FlattenedThreadIdInGroup, flattened_thread_id_in_group) + GENERATE_HLSL_INTRINSIC_FUNCTION(IsFinite, isfinite) GENERATE_HLSL_INTRINSIC_FUNCTION(IsInf, isinf) GENERATE_HLSL_INTRINSIC_FUNCTION(IsNaN, isnan) GENERATE_HLSL_INTRINSIC_FUNCTION(Rsqrt, rsqrt) diff --git a/clang/lib/Headers/hlsl/hlsl_compat_overloads.h b/clang/lib/Headers/hlsl/hlsl_compat_overloads.h index 2c0c7677be36f..fc0f3c2d069f8 100644 --- a/clang/lib/Headers/hlsl/hlsl_compat_overloads.h +++ b/clang/lib/Headers/hlsl/hlsl_compat_overloads.h @@ -378,6 +378,19 @@ _DXC_COMPAT_UNARY_INTEGER_OVERLOADS(floor) _DXC_COMPAT_UNARY_DOUBLE_OVERLOADS(frac) _DXC_COMPAT_UNARY_INTEGER_OVERLOADS(frac) +//===----------------------------------------------------------------------===// +// isfinite builtins overloads +//===----------------------------------------------------------------------===// + +_DXC_DEPRECATED_64BIT_FN(isfinite) +constexpr bool isfinite(double V) { return isfinite((float)V); } +_DXC_DEPRECATED_64BIT_FN(isfinite) +constexpr bool2 isfinite(double2 V) { return isfinite((float2)V); } +_DXC_DEPRECATED_64BIT_FN(isfinite) +constexpr bool3 isfinite(double3 V) { return isfinite((float3)V); } +_DXC_DEPRECATED_64BIT_FN(isfinite) +constexpr bool4 isfinite(double4 V) { return isfinite((float4)V); } + //===----------------------------------------------------------------------===// // isinf builtins overloads //===----------------------------------------------------------------------===// diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index 124f5bd23a623..006f71a7533b6 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -4460,6 +4460,7 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { return true; break; } + case Builtin::BI__builtin_hlsl_elementwise_isfinite: case Builtin::BI__builtin_hlsl_elementwise_isinf: case Builtin::BI__builtin_hlsl_elementwise_isnan: { if (SemaRef.checkArgCount(TheCall, 1)) diff --git a/clang/test/CodeGenHLSL/builtins/isfinite-overloads.hlsl b/clang/test/CodeGenHLSL/builtins/isfinite-overloads.hlsl new file mode 100644 index 0000000000000..d84c94d8c739c --- /dev/null +++ b/clang/test/CodeGenHLSL/builtins/isfinite-overloads.hlsl @@ -0,0 +1,37 @@ +// RUN: %clang_cc1 -std=hlsl202x -finclude-default-header -x hlsl -triple \ +// RUN: dxil-pc-shadermodel6.3-library %s -emit-llvm \ +// RUN: -Wdeprecated-declarations -o - | FileCheck %s --check-prefixes=CHECK \ +// RUN: -DFNATTRS="hidden noundef" -DTARGET=dx +// RUN: %clang_cc1 -std=hlsl202x -finclude-default-header -x hlsl -triple \ +// RUN: spirv-unknown-vulkan-library %s -emit-llvm \ +// RUN: -Wdeprecated-declarations -o - | FileCheck %s --check-prefixes=CHECK \ +// RUN: -DFNATTRS="hidden spir_func noundef" -DTARGET=spv +// RUN: %clang_cc1 -std=hlsl202x -finclude-default-header -x hlsl -triple dxil-pc-shadermodel6.3-library %s \ +// RUN: -verify -verify-ignore-unexpected=note +// RUN: %clang_cc1 -std=hlsl202x -finclude-default-header -x hlsl -triple spirv-unknown-vulkan-library %s \ +// RUN: -verify -verify-ignore-unexpected=note + +// CHECK: define [[FNATTRS]] i1 @_Z20test_isfinite_doubled( +// CHECK: [[CONVI:%.*]] = fptrunc {{.*}} double %{{.*}} to float +// CHECK: [[HLSLISFINITEI:%.*]] = call noundef i1 @llvm.[[TARGET]].isfinite.f32(float [[CONVI]]) +// CHECK: ret i1 [[HLSLISFINITEI]] +// expected-warning@+1 {{'isfinite' is deprecated: In 202x 64 bit API lowering for isfinite is deprecated. Explicitly cast parameters to 32 or 16 bit types.}} +bool test_isfinite_double(double p0) { return isfinite(p0); } +// CHECK: define [[FNATTRS]] <2 x i1> @_Z21test_isfinite_double2Dv2_d( +// CHECK: [[CONVI:%.*]] = fptrunc {{.*}} <2 x double> %{{.*}} to <2 x float> +// CHECK: [[HLSLISFINITEI:%.*]] = call noundef <2 x i1> @llvm.[[TARGET]].isfinite.v2f32(<2 x float> [[CONVI]]) +// CHECK: ret <2 x i1> [[HLSLISFINITEI]] +// expected-warning@+1 {{'isfinite' is deprecated: In 202x 64 bit API lowering for isfinite is deprecated. Explicitly cast parameters to 32 or 16 bit types.}} +bool2 test_isfinite_double2(double2 p0) { return isfinite(p0); } +// CHECK: define [[FNATTRS]] <3 x i1> @_Z21test_isfinite_double3Dv3_d( +// CHECK: [[CONVI:%.*]] = fptrunc {{.*}} <3 x double> %{{.*}} to <3 x float> +// CHECK: [[HLSLISFINITEI:%.*]] = call noundef <3 x i1> @llvm.[[TARGET]].isfinite.v3f32(<3 x float> [[CONVI]]) +// CHECK: ret <3 x i1> [[HLSLISFINITEI]] +// expected-warning@+1 {{'isfinite' is deprecated: In 202x 64 bit API lowering for isfinite is deprecated. Explicitly cast parameters to 32 or 16 bit types.}} +bool3 test_isfinite_double3(double3 p0) { return isfinite(p0); } +// CHECK: define [[FNATTRS]] <4 x i1> @_Z21test_isfinite_double4Dv4_d( +// CHECK: [[CONVI:%.*]] = fptrunc {{.*}} <4 x double> %{{.*}} to <4 x float> +// CHECK: [[HLSLISFINITEI:%.*]] = call noundef <4 x i1> @llvm.[[TARGET]].isfinite.v4f32(<4 x float> [[CONVI]]) +// CHECK: ret <4 x i1> [[HLSLISFINITEI]] +// expected-warning@+1 {{'isfinite' is deprecated: In 202x 64 bit API lowering for isfinite is deprecated. Explicitly cast parameters to 32 or 16 bit types.}} +bool4 test_isfinite_double4(double4 p0) { return isfinite(p0); } diff --git a/clang/test/CodeGenHLSL/builtins/isfinite.hlsl b/clang/test/CodeGenHLSL/builtins/isfinite.hlsl new file mode 100644 index 0000000000000..d05534a5df7bb --- /dev/null +++ b/clang/test/CodeGenHLSL/builtins/isfinite.hlsl @@ -0,0 +1,62 @@ +// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \ +// RUN: dxil-pc-shadermodel6.3-library %s -fnative-half-type -fnative-int16-type \ +// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s \ +// RUN: --check-prefixes=CHECK,DXCHECK,NATIVE_HALF +// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \ +// RUN: dxil-pc-shadermodel6.3-library %s -emit-llvm -disable-llvm-passes \ +// RUN: -o - | FileCheck %s --check-prefixes=CHECK,DXCHECK,NO_HALF + +// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \ +// RUN: spirv-unknown-vulkan-library %s -fnative-half-type -fnative-int16-type \ +// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s \ +// RUN: --check-prefixes=CHECK,SPVCHECK,NATIVE_HALF +// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \ +// RUN: spirv-unknown-vulkan-library %s -emit-llvm -disable-llvm-passes \ +// RUN: -o - | FileCheck %s --check-prefixes=CHECK,SPVCHECK,NO_HALF + +// DXCHECK: define hidden [[FN_TYPE:]]noundef i1 @ +// SPVCHECK: define hidden [[FN_TYPE:spir_func ]]noundef i1 @ +// DXCHECK: %hlsl.isfinite = call i1 @llvm.[[ICF:dx]].isfinite.f32( +// SPVCHECK: %hlsl.isfinite = call i1 @llvm.[[ICF:spv]].isfinite.f32( +// CHECK: ret i1 %hlsl.isfinite +bool test_isfinite_float(float p0) { return isfinite(p0); } + +// CHECK: define hidden [[FN_TYPE]]noundef i1 @ +// NATIVE_HALF: %hlsl.isfinite = call i1 @llvm.[[ICF]].isfinite.f16( +// NO_HALF: %hlsl.isfinite = call i1 @llvm.[[ICF]].isfinite.f32( +// CHECK: ret i1 %hlsl.isfinite +bool test_isfinite_half(half p0) { return isfinite(p0); } + +// CHECK: define hidden [[FN_TYPE]]noundef <2 x i1> @ +// NATIVE_HALF: %hlsl.isfinite = call <2 x i1> @llvm.[[ICF]].isfinite.v2f16 +// NO_HALF: %hlsl.isfinite = call <2 x i1> @llvm.[[ICF]].isfinite.v2f32( +// CHECK: ret <2 x i1> %hlsl.isfinite +bool2 test_isfinite_half2(half2 p0) { return isfinite(p0); } + +// NATIVE_HALF: define hidden [[FN_TYPE]]noundef <3 x i1> @ +// NATIVE_HALF: %hlsl.isfinite = call <3 x i1> @llvm.[[ICF]].isfinite.v3f16 +// NO_HALF: %hlsl.isfinite = call <3 x i1> @llvm.[[ICF]].isfinite.v3f32( +// CHECK: ret <3 x i1> %hlsl.isfinite +bool3 test_isfinite_half3(half3 p0) { return isfinite(p0); } + +// NATIVE_HALF: define hidden [[FN_TYPE]]noundef <4 x i1> @ +// NATIVE_HALF: %hlsl.isfinite = call <4 x i1> @llvm.[[ICF]].isfinite.v4f16 +// NO_HALF: %hlsl.isfinite = call <4 x i1> @llvm.[[ICF]].isfinite.v4f32( +// CHECK: ret <4 x i1> %hlsl.isfinite +bool4 test_isfinite_half4(half4 p0) { return isfinite(p0); } + + +// CHECK: define hidden [[FN_TYPE]]noundef <2 x i1> @ +// CHECK: %hlsl.isfinite = call <2 x i1> @llvm.[[ICF]].isfinite.v2f32 +// CHECK: ret <2 x i1> %hlsl.isfinite +bool2 test_isfinite_float2(float2 p0) { return isfinite(p0); } + +// CHECK: define hidden [[FN_TYPE]]noundef <3 x i1> @ +// CHECK: %hlsl.isfinite = call <3 x i1> @llvm.[[ICF]].isfinite.v3f32 +// CHECK: ret <3 x i1> %hlsl.isfinite +bool3 test_isfinite_float3(float3 p0) { return isfinite(p0); } + +// CHECK: define hidden [[FN_TYPE]]noundef <4 x i1> @ +// CHECK: %hlsl.isfinite = call <4 x i1> @llvm.[[ICF]].isfinite.v4f32 +// CHECK: ret <4 x i1> %hlsl.isfinite +bool4 test_isfinite_float4(float4 p0) { return isfinite(p0); } diff --git a/clang/test/SemaHLSL/BuiltIns/isfinite-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/isfinite-errors.hlsl new file mode 100644 index 0000000000000..03892c50fa65d --- /dev/null +++ b/clang/test/SemaHLSL/BuiltIns/isfinite-errors.hlsl @@ -0,0 +1,27 @@ + +// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -fnative-int16-type -emit-llvm-only -disable-llvm-passes -verify + +bool test_too_few_arg() { + return __builtin_hlsl_elementwise_isfinite(); + // expected-error@-1 {{too few arguments to function call, expected 1, have 0}} +} + +bool2 test_too_many_arg(float2 p0) { + return __builtin_hlsl_elementwise_isfinite(p0, p0); + // expected-error@-1 {{too many arguments to function call, expected 1, have 2}} +} + +bool builtin_bool_to_float_type_promotion(bool p1) { + return __builtin_hlsl_elementwise_isfinite(p1); + // expected-error@-1 {{1st argument must be a scalar or vector of 16 or 32 bit floating-point types (was 'bool')}} +} + +bool builtin_isfinite_int_to_float_promotion(int p1) { + return __builtin_hlsl_elementwise_isfinite(p1); + // expected-error@-1 {{1st argument must be a scalar or vector of 16 or 32 bit floating-point types (was 'int')}} +} + +bool2 builtin_isfinite_int2_to_float2_promotion(int2 p1) { + return __builtin_hlsl_elementwise_isfinite(p1); + // expected-error@-1 {{1st argument must be a scalar or vector of 16 or 32 bit floating-point types (was 'int2' (aka 'vector<int, 2>'))}} +} diff --git a/llvm/include/llvm/IR/IntrinsicsDirectX.td b/llvm/include/llvm/IR/IntrinsicsDirectX.td index 2d29165e27368..a8d58408e5cce 100644 --- a/llvm/include/llvm/IR/IntrinsicsDirectX.td +++ b/llvm/include/llvm/IR/IntrinsicsDirectX.td @@ -268,6 +268,8 @@ def int_dx_dot4add_u8packed : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_i32_ty, def int_dx_frac : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>], [IntrNoMem, IntrTriviallyScalarizable]>; +def int_dx_isfinite : DefaultAttrsIntrinsic<[LLVMScalarOrSameVectorWidth<0, llvm_i1_ty>], + [llvm_anyfloat_ty], [IntrNoMem, IntrTriviallyScalarizable]>; def int_dx_isinf : DefaultAttrsIntrinsic<[LLVMScalarOrSameVectorWidth<0, llvm_i1_ty>], [llvm_anyfloat_ty], [IntrNoMem, IntrTriviallyScalarizable]>; def int_dx_isnan : DefaultAttrsIntrinsic<[LLVMScalarOrSameVectorWidth<0, llvm_i1_ty>], diff --git a/llvm/lib/Target/DirectX/DXIL.td b/llvm/lib/Target/DirectX/DXIL.td index cde3a2ca8db31..e237967ea93a4 100644 --- a/llvm/lib/Target/DirectX/DXIL.td +++ b/llvm/lib/Target/DirectX/DXIL.td @@ -476,6 +476,7 @@ def IsInf : DXILOp<9, isSpecialFloat> { def IsFinite : DXILOp<10, isSpecialFloat> { let Doc = "Determines if the specified value is finite."; + let intrinsics = [IntrinSelect<int_dx_isfinite>]; let arguments = [OverloadTy]; let result = Int1Ty; let overloads = [Overloads<DXIL1_0, [HalfTy, FloatTy]>]; diff --git a/llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp b/llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp index dce8a1ec9f92a..e7aac17b47cb7 100644 --- a/llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp +++ b/llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp @@ -225,6 +225,7 @@ static bool isIntrinsicExpansion(Function &F) { case Intrinsic::dx_uclamp: case Intrinsic::dx_sclamp: case Intrinsic::dx_nclamp: + case Intrinsic::dx_isfinite: case Intrinsic::dx_isinf: case Intrinsic::dx_isnan: case Intrinsic::dx_sdot: @@ -1331,6 +1332,9 @@ static bool expandIntrinsic(Function &F, CallInst *Orig) { case Intrinsic::dx_nclamp: Result = expandClampIntrinsic(Orig, IntrinsicId); break; + case Intrinsic::dx_isfinite: + Result = expand16BitIsFinite(Orig); + break; case Intrinsic::dx_isinf: Result = expand16BitIsInf(Orig); break; diff --git a/llvm/lib/Target/DirectX/DirectXTargetTransformInfo.cpp b/llvm/lib/Target/DirectX/DirectXTargetTransformInfo.cpp index af1d7bc452126..6c65fb7b9e0fc 100644 --- a/llvm/lib/Target/DirectX/DirectXTargetTransformInfo.cpp +++ b/llvm/lib/Target/DirectX/DirectXTargetTransformInfo.cpp @@ -32,6 +32,7 @@ bool DirectXTTIImpl::isTargetIntrinsicWithOverloadTypeAtArg(Intrinsic::ID ID, case Intrinsic::dx_firstbitlow: case Intrinsic::dx_firstbitshigh: case Intrinsic::dx_firstbituhigh: + case Intrinsic::dx_isfinite: case Intrinsic::dx_isinf: case Intrinsic::dx_isnan: case Intrinsic::dx_legacyf16tof32: diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp index 562344ac52b58..2750c7145cddb 100644 --- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp @@ -3433,11 +3433,38 @@ bool SPIRVInstructionSelector::selectOpIsNan(Register ResVReg, bool SPIRVInstructionSelector::selectOpIsFinite(Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const { + // OpIsFinite requires Kernel capability; emulate with OpIsInf & OpIsNan MachineBasicBlock &BB = *I.getParent(); - BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpIsFinite)) + Register Src = I.getOperand(2).getReg(); + Register TypeID = GR.getSPIRVTypeID(ResType); + const DebugLoc &DL = I.getDebugLoc(); + + Register IsInfReg = MRI->createVirtualRegister(&SPIRV::IDRegClass); + BuildMI(BB, I, DL, TII.get(SPIRV::OpIsInf)) + .addDef(IsInfReg) + .addUse(TypeID) + .addUse(Src) + .constrainAllUses(TII, TRI, RBI); + + Register IsNanReg = MRI->createVirtualRegister(&SPIRV::IDRegClass); + BuildMI(BB, I, DL, TII.get(SPIRV::OpIsNan)) + .addDef(IsNanReg) + .addUse(TypeID) + .addUse(Src) + .constrainAllUses(TII, TRI, RBI); + + Register OrReg = MRI->createVirtualRegister(&SPIRV::IDRegClass); + BuildMI(BB, I, DL, TII.get(SPIRV::OpLogicalOr)) + .addDef(OrReg) + .addUse(TypeID) + .addUse(IsInfReg) + .addUse(IsNanReg) + .constrainAllUses(TII, TRI, RBI); + + BuildMI(BB, I, DL, TII.get(SPIRV::OpLogicalNot)) .addDef(ResVReg) - .addUse(GR.getSPIRVTypeID(ResType)) - .addUse(I.getOperand(2).getReg()) + .addUse(TypeID) + .addUse(OrReg) .constrainAllUses(TII, TRI, RBI); return true; } diff --git a/llvm/test/CodeGen/DirectX/LongVector/isfinite.ll b/llvm/test/CodeGen/DirectX/LongVector/isfinite.ll new file mode 100644 index 0000000000000..1b1fa71a0e8c3 --- /dev/null +++ b/llvm/test/CodeGen/DirectX/LongVector/isfinite.ll @@ -0,0 +1,11 @@ +; RUN: llc -mtriple=dxil-pc-shadermodel6.8-library -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-SCALAR +; RUN: llc -mtriple=dxil-pc-shadermodel6.9-library -stop-before=dxil-op-lower -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-VECTOR + +; CHECK-LABEL: define <17 x i1> @test_isfinite( +; CHECK-SCALAR-COUNT-17: call i1 @dx.op.isSpecialFloat.f32(i32 10, float {{.*}}) +; CHECK-VECTOR: call <17 x i1> @llvm.dx.isfinite.v17f32 +define <17 x i1> @test_isfinite(<17 x float> %a) { + %result = call <17 x i1> @llvm.dx.isfinite.v17f32(<17 x float> %a) + ret <17 x i1> %result +} +declare <17 x i1> @llvm.dx.isfinite.v17f32(<17 x float>) diff --git a/llvm/test/CodeGen/DirectX/isfinite.ll b/llvm/test/CodeGen/DirectX/isfinite.ll new file mode 100644 index 0000000000000..46c04d22f9f80 --- /dev/null +++ b/llvm/test/CodeGen/DirectX/isfinite.ll @@ -0,0 +1,62 @@ +; RUN: opt -S -dxil-intrinsic-expansion -scalarizer -dxil-op-lower -mtriple=dxil-pc-shadermodel6.9-library %s | FileCheck %s --check-prefixes=CHECK,SM69CHECK +; RUN: opt -S -dxil-intrinsic-expansion -scalarizer -dxil-op-lower -mtriple=dxil-pc-shadermodel6.8-library %s | FileCheck %s --check-prefixes=CHECK,SMOLDCHECK + +; Make sure dxil operation function calls for isfinite are generated for float and half. + +define noundef i1 @isfinite_float(float noundef %a) { +entry: + ; CHECK: call i1 @dx.op.isSpecialFloat.f32(i32 10, float %{{.*}}) + %dx.isfinite = call i1 @llvm.dx.isfinite.f32(float %a) + ret i1 %dx.isfinite +} + +define noundef i1 @isfinite_half(half noundef %a) { +entry: + ; SM69CHECK: call i1 @dx.op.isSpecialFloat.f16(i32 10, half %{{.*}}) + ; SMOLDCHECK: [[BITCAST:%.*]] = bitcast half %a to i16 + ; SMOLDCHECK: [[AND:%.*]] = and i16 [[BITCAST]], 31744 + ; SMOLDCHECK: [[CMP:%.*]] = icmp ne i16 [[AND]], 31744 + %dx.isfinite = call i1 @llvm.dx.isfinite.f16(half %a) + ret i1 %dx.isfinite +} + +define noundef <4 x i1> @isfinite_half4(<4 x half> noundef %p0) { +entry: + ; SM69CHECK: call i1 @dx.op.isSpecialFloat.f16(i32 10, half + ; SM69CHECK: call i1 @dx.op.isSpecialFloat.f16(i32 10, half + ; SM69CHECK: call i1 @dx.op.isSpecialFloat.f16(i32 10, half + ; SM69CHECK: call i1 @dx.op.isSpecialFloat.f16(i32 10, half + + ; SMOLDCHECK: [[ee0:%.*]] = extractelement <4 x half> %p0, i64 0 + ; SMOLDCHECK: [[BITCAST0:%.*]] = bitcast half [[ee0]] to i16 + ; SMOLDCHECK: [[ee1:%.*]] = extractelement <4 x half> %p0, i64 1 + ; SMOLDCHECK: [[BITCAST1:%.*]] = bitcast half [[ee1]] to i16 + ; SMOLDCHECK: [[ee2:%.*]] = extractelement <4 x half> %p0, i64 2 + ; SMOLDCHECK: [[BITCAST2:%.*]] = bitcast half [[ee2]] to i16 + ; SMOLDCHECK: [[ee3:%.*]] = extractelement <4 x half> %p0, i64 3 + ; SMOLDCHECK: [[BITCAST3:%.*]] = bitcast half [[ee3]] to i16 + ; SMOLDCHECK: [[AND0:%.*]] = and i16 [[BITCAST0]], 31744 + ; SMOLDCHECK: [[AND1:%.*]] = and i16 [[BITCAST1]], 31744 + ; SMOLDCHECK: [[AND2:%.*]] = and i16 [[BITCAST2]], 31744 + ; SMOLDCHECK: [[AND3:%.*]] = and i16 [[BITCAST3]], 31744 + ; SMOLDCHECK: [[CMP0:%.*]] = icmp ne i16 [[AND0]], 31744 + ; SMOLDCHECK: [[CMP1:%.*]] = icmp ne i16 [[AND1]], 31744 + ; SMOLDCHECK: [[CMP2:%.*]] = icmp ne i16 [[AND2]], 31744 + ; SMOLDCHECK: [[CMP3:%.*]] = icmp ne i16 [[AND3]], 31744 + + %hlsl.isfinite = call <4 x i1> @llvm.dx.isfinite.v4f16(<4 x half> %p0) + ret <4 x i1> %hlsl.isfinite +} + +define noundef <3 x i1> @isfinite_float3(<3 x float> noundef %p0) { +entry: + ; CHECK: call i1 @dx.op.isSpecialFloat.f32(i32 10, float + ; CHECK: call i1 @dx.op.isSpecialFloat.f32(i32 10, float + ; CHECK: call i1 @dx.op.isSpecialFloat.f32(i32 10, float + %hlsl.isfinite = call <3 x i1> @llvm.dx.isfinite.v3f32(<3 x float> %p0) + ret <3 x i1> %hlsl.isfinite +} + +; CHECK-DAG: declare i1 @dx.op.isSpecialFloat.f32(i32, float) #[[#ATTR0:]] +; SM69CHECK-DAG: declare i1 @dx.op.isSpecialFloat.f16(i32, half) #[[#ATTR0]] +; CHECK: attributes #[[#ATTR0]] = { nounwind memory(none) } diff --git a/llvm/test/CodeGen/DirectX/isfinite_error.ll b/llvm/test/CodeGen/DirectX/isfinite_error.ll new file mode 100644 index 0000000000000..03dd513f99ac0 --- /dev/null +++ b/llvm/test/CodeGen/DirectX/isfinite_error.ll @@ -0,0 +1,14 @@ +; RUN: not opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s 2>&1 | FileCheck %s + +; DXIL operation isfinite does not support double overload type +; CHECK: in function isfinite_double +; CHECK-SAME: Cannot create IsFinite operation: Invalid overload type + +define noundef i1 @isfinite_double(double noundef %a) #0 { +entry: + %a.addr = alloca double, align 8 + store double %a, ptr %a.addr, align 8 + %0 = load double, ptr %a.addr, align 8 + %dx.isfinite = call i1 @llvm.dx.isfinite.f64(double %0) + ret i1 %dx.isfinite +} diff --git a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/OpIsFinite.ll b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/OpIsFinite.ll index 0455e715a349d..4829558aa3e3b 100644 --- a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/OpIsFinite.ll +++ b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/OpIsFinite.ll @@ -12,7 +12,10 @@ define noundef i1 @isfinite_half(half noundef %a) { entry: ; CHECK: %[[#]] = OpFunction %[[#bool]] None %[[#]] ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#float_16]] - ; CHECK: %[[#]] = OpIsFinite %[[#bool]] %[[#arg0]] + ; CHECK: %[[#isinf:]] = OpIsInf %[[#bool]] %[[#arg0]] + ; CHECK: %[[#isnan:]] = OpIsNan %[[#bool]] %[[#arg0]] + ; CHECK: %[[#or:]] = OpLogicalOr %[[#bool]] %[[#isinf]] %[[#isnan]] + ; CHECK: %[[#]] = OpLogicalNot %[[#bool]] %[[#or]] %hlsl.isfinite = call i1 @llvm.spv.isfinite.f16(half %a) ret i1 %hlsl.isfinite } @@ -21,7 +24,10 @@ define noundef i1 @isfinite_float(float noundef %a) { entry: ; CHECK: %[[#]] = OpFunction %[[#bool]] None %[[#]] ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#float_32]] - ; CHECK: %[[#]] = OpIsFinite %[[#bool]] %[[#arg0]] + ; CHECK: %[[#isinf:]] = OpIsInf %[[#bool]] %[[#arg0]] + ; CHECK: %[[#isnan:]] = OpIsNan %[[#bool]] %[[#arg0]] + ; CHECK: %[[#or:]] = OpLogicalOr %[[#bool]] %[[#isinf]] %[[#isnan]] + ; CHECK: %[[#]] = OpLogicalNot %[[#bool]] %[[#or]] %hlsl.isfinite = call i1 @llvm.spv.isfinite.f32(float %a) ret i1 %hlsl.isfinite } @@ -30,7 +36,10 @@ define noundef <4 x i1> @isfinite_half4(<4 x half> noundef %a) { entry: ; CHECK: %[[#]] = OpFunction %[[#vec4_bool]] None %[[#]] ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#vec4_float_16]] - ; CHECK: %[[#]] = OpIsFinite %[[#vec4_bool]] %[[#arg0]] + ; CHECK: %[[#isinf:]] = OpIsInf %[[#vec4_bool]] %[[#arg0]] + ; CHECK: %[[#isnan:]] = OpIsNan %[[#vec4_bool]] %[[#arg0]] + ; CHECK: %[[#or:]] = OpLogicalOr %[[#vec4_bool]] %[[#isinf]] %[[#isnan]] + ; CHECK: %[[#]] = OpLogicalNot %[[#vec4_bool]] %[[#or]] %hlsl.isfinite = call <4 x i1> @llvm.spv.isfinite.v4f16(<4 x half> %a) ret <4 x i1> %hlsl.isfinite } @@ -39,7 +48,10 @@ define noundef <4 x i1> @isfinite_float4(<4 x float> noundef %a) { entry: ; CHECK: %[[#]] = OpFunction %[[#vec4_bool]] None %[[#]] ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#vec4_float_32]] - ; CHECK: %[[#]] = OpIsFinite %[[#vec4_bool]] %[[#arg0]] + ; CHECK: %[[#isinf:]] = OpIsInf %[[#vec4_bool]] %[[#arg0]] + ; CHECK: %[[#isnan:]] = OpIsNan %[[#vec4_bool]] %[[#arg0]] + ; CHECK: %[[#or:]] = OpLogicalOr %[[#vec4_bool]] %[[#isinf]] %[[#isnan]] + ; CHECK: %[[#]] = OpLogicalNot %[[#vec4_bool]] %[[#or]] %hlsl.isfinite = call <4 x i1> @llvm.spv.isfinite.v4f32(<4 x float> %a) ret <4 x i1> %hlsl.isfinite } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
