https://github.com/danbrown-amd updated 
https://github.com/llvm/llvm-project/pull/225947

>From 28c0cb5bc4ba802a1c3682052618ad753568e520 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 c438ca03eb6877..f6d97c58ceaccf 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -5744,6 +5744,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 10adf4fb676ee0..6369def55f2c7c 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 84808e7f88c6ac..21626d32d4cabf 100644
--- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp
+++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
@@ -1201,6 +1201,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 f551bb006ea2c1..567cf13996e8d6 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 2c0c7677be36fc..fc0f3c2d069f85 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 4f5e41feb95619..c52ca22a8af7c4 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -4436,6 +4436,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 00000000000000..d84c94d8c739c0
--- /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 00000000000000..caf234cb4bfe95
--- /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-compute %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-compute %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 00000000000000..03892c50fa65d1
--- /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 2d29165e273681..a8d58408e5cceb 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 cde3a2ca8db311..e237967ea93a48 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 dce8a1ec9f92a0..e7aac17b47cb79 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 af1d7bc4521263..6c65fb7b9e0fc7 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 562344ac52b581..2750c7145cddbd 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 00000000000000..1b1fa71a0e8c32
--- /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 00000000000000..46c04d22f9f80c
--- /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 00000000000000..03dd513f99ac0e
--- /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 0455e715a349d2..4829558aa3e3bd 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

Reply via email to