https://github.com/danbrown-amd created 
https://github.com/llvm/llvm-project/pull/157733

Addresses #99132.

>From 3b58c7916dad497815b787071d1e384d55703eb8 Mon Sep 17 00:00:00 2001
From: Dan Brown <danbr...@amd.com>
Date: Tue, 9 Sep 2025 12:40:57 -0600
Subject: [PATCH] Implements isnan() HLSL intrinsic for DXIL and SPIR-V
 targets. Addresses #99132.

---
 clang/include/clang/Basic/Builtins.td         |  6 ++
 clang/lib/CodeGen/CGHLSLBuiltins.cpp          | 15 +++++
 clang/lib/CodeGen/CGHLSLRuntime.h             |  1 +
 .../lib/Headers/hlsl/hlsl_alias_intrinsics.h  | 33 ++++++++++
 .../lib/Headers/hlsl/hlsl_compat_overloads.h  |  9 +++
 clang/lib/Headers/hlsl/hlsl_intrinsics.h      | 37 +++++++++++
 clang/lib/Sema/SemaHLSL.cpp                   |  3 +-
 .../CodeGenHLSL/builtins/isnan-overloads.hlsl | 20 ++++++
 clang/test/CodeGenHLSL/builtins/isnan.hlsl    | 62 +++++++++++++++++++
 .../test/SemaHLSL/BuiltIns/isnan-errors.hlsl  | 38 ++++++++++++
 llvm/include/llvm/IR/IntrinsicsDirectX.td     |  2 +
 llvm/include/llvm/IR/IntrinsicsSPIRV.td       |  2 +
 .../Target/SPIRV/SPIRVInstructionSelector.cpp | 16 +++++
 .../CodeGen/SPIRV/hlsl-intrinsics/isnan.ll    | 45 ++++++++++++++
 14 files changed, 288 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/CodeGenHLSL/builtins/isnan-overloads.hlsl
 create mode 100644 clang/test/CodeGenHLSL/builtins/isnan.hlsl
 create mode 100644 clang/test/SemaHLSL/BuiltIns/isnan-errors.hlsl
 create mode 100644 llvm/test/CodeGen/SPIRV/hlsl-intrinsics/isnan.ll

diff --git a/clang/include/clang/Basic/Builtins.td 
b/clang/include/clang/Basic/Builtins.td
index 27639f06529cb..6d23d616d5ae7 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -5083,6 +5083,12 @@ def HLSLIsinf : LangBuiltin<"HLSL_LANG"> {
   let Prototype = "void(...)";
 }
 
+def HLSLIsnan : LangBuiltin<"HLSL_LANG"> {
+  let Spellings = ["__builtin_hlsl_elementwise_isnan"];
+  let Attributes = [NoThrow, Const];
+  let Prototype = "int(...)";
+}
+
 def HLSLLerp : LangBuiltin<"HLSL_LANG"> {
   let Spellings = ["__builtin_hlsl_lerp"];
   let Attributes = [NoThrow, Const, CustomTypeChecking];
diff --git a/clang/lib/CodeGen/CGHLSLBuiltins.cpp 
b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
index 5004c09e0d5cf..775f11103febe 100644
--- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp
+++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
@@ -540,6 +540,21 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned 
BuiltinID,
         retType, CGM.getHLSLRuntime().getIsInfIntrinsic(),
         ArrayRef<Value *>{Op0}, nullptr, "hlsl.isinf");
   }
+  case Builtin::BI__builtin_hlsl_elementwise_isnan: {
+    Value *Op0 = EmitScalarExpr(E->getArg(0));
+    llvm::Type *Xty = Op0->getType();
+    llvm::Type *retType = llvm::Type::getInt1Ty(this->getLLVMContext());
+    if (Xty->isVectorTy()) {
+      auto *XVecTy = E->getArg(0)->getType()->castAs<VectorType>();
+      retType = llvm::VectorType::get(
+          retType, ElementCount::getFixed(XVecTy->getNumElements()));
+    }
+    if (!E->getArg(0)->getType()->hasFloatingRepresentation())
+      llvm_unreachable("isnan operand must have a float representation");
+    return Builder.CreateIntrinsic(
+        retType, CGM.getHLSLRuntime().getIsNaNIntrinsic(),
+        ArrayRef<Value *>{Op0}, nullptr, "hlsl.isnan");
+  }
   case Builtin::BI__builtin_hlsl_mad: {
     Value *M = EmitScalarExpr(E->getArg(0));
     Value *A = EmitScalarExpr(E->getArg(1));
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h 
b/clang/lib/CodeGen/CGHLSLRuntime.h
index 0582be3d99ec4..254d78207190f 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -92,6 +92,7 @@ class CGHLSLRuntime {
   GENERATE_HLSL_INTRINSIC_FUNCTION(FlattenedThreadIdInGroup,
                                    flattened_thread_id_in_group)
   GENERATE_HLSL_INTRINSIC_FUNCTION(IsInf, isinf)
+  GENERATE_HLSL_INTRINSIC_FUNCTION(IsNaN, isnan)
   GENERATE_HLSL_INTRINSIC_FUNCTION(Lerp, lerp)
   GENERATE_HLSL_INTRINSIC_FUNCTION(Normalize, normalize)
   GENERATE_HLSL_INTRINSIC_FUNCTION(Rsqrt, rsqrt)
diff --git a/clang/lib/Headers/hlsl/hlsl_alias_intrinsics.h 
b/clang/lib/Headers/hlsl/hlsl_alias_intrinsics.h
index 21a9c30d9f445..84e1de3dc23e9 100644
--- a/clang/lib/Headers/hlsl/hlsl_alias_intrinsics.h
+++ b/clang/lib/Headers/hlsl/hlsl_alias_intrinsics.h
@@ -1292,6 +1292,39 @@ bool3 isinf(float3);
 _HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_isinf)
 bool4 isinf(float4);
 
+//===----------------------------------------------------------------------===//
+// isnan builtins
+//===----------------------------------------------------------------------===//
+
+/// \fn T isnan(T x)
+/// \brief Determines if the specified value \a x  is Not a Number.
+/// \param x The specified input value.
+///
+/// Returns a value of the same size as the input, with a value set
+/// to True if the x parameter is NaN or QNaN. Otherwise, False.
+
+_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_isnan)
+bool isnan(half);
+_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_isnan)
+bool2 isnan(half2);
+_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_isnan)
+bool3 isnan(half3);
+_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_isnan)
+bool4 isnan(half4);
+
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_isnan)
+bool isnan(float);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_isnan)
+bool2 isnan(float2);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_isnan)
+bool3 isnan(float3);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_isnan)
+bool4 isnan(float4);
+
 
//===----------------------------------------------------------------------===//
 // lerp builtins
 
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/Headers/hlsl/hlsl_compat_overloads.h 
b/clang/lib/Headers/hlsl/hlsl_compat_overloads.h
index 4874206d349c0..030ce11ba6015 100644
--- a/clang/lib/Headers/hlsl/hlsl_compat_overloads.h
+++ b/clang/lib/Headers/hlsl/hlsl_compat_overloads.h
@@ -273,6 +273,15 @@ constexpr bool2 isinf(double2 V) { return 
isinf((float2)V); }
 constexpr bool3 isinf(double3 V) { return isinf((float3)V); }
 constexpr bool4 isinf(double4 V) { return isinf((float4)V); }
 
+//===----------------------------------------------------------------------===//
+// isnan builtins overloads
+//===----------------------------------------------------------------------===//
+
+constexpr bool isnan(double V) { return isnan((float)V); }
+constexpr bool2 isnan(double2 V) { return isnan((float2)V); }
+constexpr bool3 isnan(double3 V) { return isnan((float3)V); }
+constexpr bool4 isnan(double4 V) { return isnan((float4)V); }
+
 
//===----------------------------------------------------------------------===//
 // lerp builtins overloads
 
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h 
b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
index d9d87c827e6a4..ab0c5faad7031 100644
--- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h
+++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
@@ -303,6 +303,43 @@ fmod(__detail::HLSL_FIXED_VECTOR<float, N> X,
   return __detail::fmod_vec_impl(X, Y);
 }
 
+//===----------------------------------------------------------------------===//
+// isnan builtins
+//===----------------------------------------------------------------------===//
+
+/// \fn bool isnan(T x)
+/// \brief Returns whether x is NaN or QNaN.
+/// \param x [in] A number or vector of numbers.
+///
+/// Return whether (each element of) x is NaN or QNaN.
+
+template <typename T>
+_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
+const inline __detail::enable_if_t<
+    __detail::is_arithmetic<T>::Value && __detail::is_same<half, T>::value, T>
+isnan(T X) {
+  return __builtin_elementwise_isnan(X);
+}
+template <typename T>
+const inline __detail::enable_if_t<
+    __detail::is_arithmetic<T>::Value && __detail::is_same<float, T>::value, T>
+isnan(T X) {
+  return __builtin_elementwise_isnan(X);
+}
+
+template <int N>
+_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
+const inline __detail::HLSL_FIXED_VECTOR<half, N>
+isnan(__detail::HLSL_FIXED_VECTOR<half, N> X) {
+  return __builtin_elementwise_isnan(X);
+}
+
+template <int N>
+const inline __detail::HLSL_FIXED_VECTOR<float, N>
+isnan(__detail::HLSL_FIXED_VECTOR<float, N> X) {
+  return __builtin_elementwise_isnan(X);
+}
+
 
//===----------------------------------------------------------------------===//
 // ldexp builtins
 
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index fb8f131d1e11b..2be0e06adf236 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -2990,7 +2990,8 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned 
BuiltinID, CallExpr *TheCall) {
       return true;
     break;
   }
-  case Builtin::BI__builtin_hlsl_elementwise_isinf: {
+  case Builtin::BI__builtin_hlsl_elementwise_isinf:
+  case Builtin::BI__builtin_hlsl_elementwise_isnan: {
     if (SemaRef.checkArgCount(TheCall, 1))
       return true;
     if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
diff --git a/clang/test/CodeGenHLSL/builtins/isnan-overloads.hlsl 
b/clang/test/CodeGenHLSL/builtins/isnan-overloads.hlsl
new file mode 100644
index 0000000000000..a0c3eee5da636
--- /dev/null
+++ b/clang/test/CodeGenHLSL/builtins/isnan-overloads.hlsl
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -std=hlsl202x -finclude-default-header -x hlsl -triple \
+// RUN:   dxil-pc-shadermodel6.3-library %s -emit-llvm -disable-llvm-passes \
+// RUN:   -o - | FileCheck %s
+
+// CHECK: define hidden noundef i1 @
+// CHECK: %hlsl.isnan = call i1 @llvm.dx.isnan.f32(
+// CHECK: ret i1 %hlsl.isnan
+bool test_isnan_double(double p0) { return isnan(p0); }
+// CHECK: define hidden noundef <2 x i1> @
+// CHECK: %hlsl.isnan = call <2 x i1> @llvm.dx.isnan.v2f32
+// CHECK: ret <2 x i1> %hlsl.isnan
+bool2 test_isnan_double2(double2 p0) { return isnan(p0); }
+// CHECK: define hidden noundef <3 x i1> @
+// CHECK: %hlsl.isnan = call <3 x i1> @llvm.dx.isnan.v3f32
+// CHECK: ret <3 x i1> %hlsl.isnan
+bool3 test_isnan_double3(double3 p0) { return isnan(p0); }
+// CHECK: define hidden noundef <4 x i1> @
+// CHECK: %hlsl.isnan = call <4 x i1> @llvm.dx.isnan.v4f32
+// CHECK: ret <4 x i1> %hlsl.isnan
+bool4 test_isnan_double4(double4 p0) { return isnan(p0); }
diff --git a/clang/test/CodeGenHLSL/builtins/isnan.hlsl 
b/clang/test/CodeGenHLSL/builtins/isnan.hlsl
new file mode 100644
index 0000000000000..ce7dbe1aedea4
--- /dev/null
+++ b/clang/test/CodeGenHLSL/builtins/isnan.hlsl
@@ -0,0 +1,62 @@
+// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
+// RUN:   dxil-pc-shadermodel6.3-library %s -fnative-half-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 \
+// 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.isnan = call i1 @llvm.[[ICF:dx]].isnan.f32(
+// SPVCHECK: %hlsl.isnan = call i1 @llvm.[[ICF:spv]].isnan.f32(
+// CHECK: ret i1 %hlsl.isnan
+bool test_isnan_float(float p0) { return isnan(p0); }
+
+// CHECK: define hidden [[FN_TYPE]]noundef i1 @
+// NATIVE_HALF: %hlsl.isnan = call i1 @llvm.[[ICF]].isnan.f16(
+// NO_HALF: %hlsl.isnan = call i1 @llvm.[[ICF]].isnan.f32(
+// CHECK: ret i1 %hlsl.isnan
+bool test_isnan_half(half p0) { return isnan(p0); }
+
+// CHECK: define hidden [[FN_TYPE]]noundef <2 x i1> @
+// NATIVE_HALF: %hlsl.isnan = call <2 x i1> @llvm.[[ICF]].isnan.v2f16
+// NO_HALF: %hlsl.isnan = call <2 x i1> @llvm.[[ICF]].isnan.v2f32(
+// CHECK: ret <2 x i1> %hlsl.isnan
+bool2 test_isnan_half2(half2 p0) { return isnan(p0); }
+
+// NATIVE_HALF: define hidden [[FN_TYPE]]noundef <3 x i1> @
+// NATIVE_HALF: %hlsl.isnan = call <3 x i1> @llvm.[[ICF]].isnan.v3f16
+// NO_HALF: %hlsl.isnan = call <3 x i1> @llvm.[[ICF]].isnan.v3f32(
+// CHECK: ret <3 x i1> %hlsl.isnan
+bool3 test_isnan_half3(half3 p0) { return isnan(p0); }
+
+// NATIVE_HALF: define hidden [[FN_TYPE]]noundef <4 x i1> @
+// NATIVE_HALF: %hlsl.isnan = call <4 x i1> @llvm.[[ICF]].isnan.v4f16
+// NO_HALF: %hlsl.isnan = call <4 x i1> @llvm.[[ICF]].isnan.v4f32(
+// CHECK: ret <4 x i1> %hlsl.isnan
+bool4 test_isnan_half4(half4 p0) { return isnan(p0); }
+
+
+// CHECK: define hidden [[FN_TYPE]]noundef <2 x i1> @
+// CHECK: %hlsl.isnan = call <2 x i1> @llvm.[[ICF]].isnan.v2f32
+// CHECK: ret <2 x i1> %hlsl.isnan
+bool2 test_isnan_float2(float2 p0) { return isnan(p0); }
+
+// CHECK: define hidden [[FN_TYPE]]noundef <3 x i1> @
+// CHECK: %hlsl.isnan = call <3 x i1> @llvm.[[ICF]].isnan.v3f32
+// CHECK: ret <3 x i1> %hlsl.isnan
+bool3 test_isnan_float3(float3 p0) { return isnan(p0); }
+
+// CHECK: define hidden [[FN_TYPE]]noundef <4 x i1> @
+// CHECK: %hlsl.isnan = call <4 x i1> @llvm.[[ICF]].isnan.v4f32
+// CHECK: ret <4 x i1> %hlsl.isnan
+bool4 test_isnan_float4(float4 p0) { return isnan(p0); }
diff --git a/clang/test/SemaHLSL/BuiltIns/isnan-errors.hlsl 
b/clang/test/SemaHLSL/BuiltIns/isnan-errors.hlsl
new file mode 100644
index 0000000000000..a6be28117af4f
--- /dev/null
+++ b/clang/test/SemaHLSL/BuiltIns/isnan-errors.hlsl
@@ -0,0 +1,38 @@
+
+// RUN: %clang_cc1 -finclude-default-header -triple 
dxil-pc-shadermodel6.6-library %s -fnative-half-type -emit-llvm-only 
-disable-llvm-passes -verify
+
+bool test_too_few_arg() {
+  return __builtin_hlsl_elementwise_isnan();
+  // expected-error@-1 {{too few arguments to function call, expected 1, have 
0}}
+}
+
+bool2 test_too_many_arg(float2 p0) {
+  return __builtin_hlsl_elementwise_isnan(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_isnan(p1);
+  // expected-error@-1 {{1st argument must be a scalar or vector of 16 or 32 
bit floating-point types (was 'bool')}}
+}
+
+bool builtin_isnan_int_to_float_promotion(int p1) {
+  return __builtin_hlsl_elementwise_isnan(p1);
+  // expected-error@-1 {{1st argument must be a scalar or vector of 16 or 32 
bit floating-point types (was 'int')}}
+}
+
+bool2 builtin_isnan_int2_to_float2_promotion(int2 p1) {
+  return __builtin_hlsl_elementwise_isnan(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>'))}}
+}
+
+// builtins are variadic functions and so are subject to 
DefaultVariadicArgumentPromotion
+half builtin_isnan_half_scalar (half p0) {
+  return __builtin_hlsl_elementwise_isnan (p0);
+  // expected-error@-1 {{1st argument must be a scalar or vector of 16 or 32 
bit floating-point types (was 'double')}}
+}
+
+float builtin_isnan_float_scalar ( float p0) {
+  return __builtin_hlsl_elementwise_isnan (p0);
+  // expected-error@-1 {{1st argument must be a scalar or vector of 16 or 32 
bit floating-point types (was 'double')}}
+}
diff --git a/llvm/include/llvm/IR/IntrinsicsDirectX.td 
b/llvm/include/llvm/IR/IntrinsicsDirectX.td
index 5d76c3f8df89d..fab918caca816 100644
--- a/llvm/include/llvm/IR/IntrinsicsDirectX.td
+++ b/llvm/include/llvm/IR/IntrinsicsDirectX.td
@@ -130,6 +130,8 @@ def int_dx_degrees : 
DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty
 
 def int_dx_isinf : DefaultAttrsIntrinsic<[LLVMScalarOrSameVectorWidth<0, 
llvm_i1_ty>],
     [llvm_anyfloat_ty], [IntrNoMem]>;
+def int_dx_isnan : DefaultAttrsIntrinsic<[LLVMScalarOrSameVectorWidth<0, 
llvm_i1_ty>],
+    [llvm_anyfloat_ty], [IntrNoMem]>;
 
 def int_dx_lerp : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty, 
LLVMMatchType<0>,LLVMMatchType<0>],
     [IntrNoMem]>;
diff --git a/llvm/include/llvm/IR/IntrinsicsSPIRV.td 
b/llvm/include/llvm/IR/IntrinsicsSPIRV.td
index bc026fa33c769..395665f336a69 100644
--- a/llvm/include/llvm/IR/IntrinsicsSPIRV.td
+++ b/llvm/include/llvm/IR/IntrinsicsSPIRV.td
@@ -87,6 +87,8 @@ let TargetPrefix = "spv" in {
   def int_spv_frac : DefaultAttrsIntrinsic<[LLVMMatchType<0>], 
[llvm_anyfloat_ty], [IntrNoMem]>;
   def int_spv_isinf : DefaultAttrsIntrinsic<[LLVMScalarOrSameVectorWidth<0, 
llvm_i1_ty>],
     [llvm_anyfloat_ty], [IntrNoMem]>;
+  def int_spv_isnan : DefaultAttrsIntrinsic<[LLVMScalarOrSameVectorWidth<0, 
llvm_i1_ty>],
+    [llvm_anyfloat_ty], [IntrNoMem]>;
   def int_spv_lerp : DefaultAttrsIntrinsic<[LLVMMatchType<0>], 
[llvm_anyfloat_ty, LLVMMatchType<0>,LLVMMatchType<0>],
     [IntrNoMem] >;
   def int_spv_length : DefaultAttrsIntrinsic<[LLVMVectorElementType<0>], 
[llvm_anyfloat_ty], [IntrNoMem]>;
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp 
b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index 3ad5528fab061..38dda2c686939 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -207,6 +207,9 @@ class SPIRVInstructionSelector : public InstructionSelector 
{
   bool selectOpIsInf(Register ResVReg, const SPIRVType *ResType,
                      MachineInstr &I) const;
 
+  bool selectOpIsNan(Register ResVReg, const SPIRVType *ResType,
+                     MachineInstr &I) const;
+
   template <bool Signed>
   bool selectDot4AddPacked(Register ResVReg, const SPIRVType *ResType,
                            MachineInstr &I) const;
@@ -2056,6 +2059,17 @@ bool SPIRVInstructionSelector::selectOpIsInf(Register 
ResVReg,
       .constrainAllUses(TII, TRI, RBI);
 }
 
+bool SPIRVInstructionSelector::selectOpIsNan(Register ResVReg,
+                                             const SPIRVType *ResType,
+                                             MachineInstr &I) const {
+  MachineBasicBlock &BB = *I.getParent();
+  return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpIsNan))
+      .addDef(ResVReg)
+      .addUse(GR.getSPIRVTypeID(ResType))
+      .addUse(I.getOperand(2).getReg())
+      .constrainAllUses(TII, TRI, RBI);
+}
+
 template <bool Signed>
 bool SPIRVInstructionSelector::selectDot4AddPacked(Register ResVReg,
                                                    const SPIRVType *ResType,
@@ -3199,6 +3213,8 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register 
ResVReg,
     return selectExtInst(ResVReg, ResType, I, CL::fract, GL::Fract);
   case Intrinsic::spv_isinf:
     return selectOpIsInf(ResVReg, ResType, I);
+  case Intrinsic::spv_isnan:
+    return selectOpIsNan(ResVReg, ResType, I);
   case Intrinsic::spv_normalize:
     return selectExtInst(ResVReg, ResType, I, CL::normalize, GL::Normalize);
   case Intrinsic::spv_refract:
diff --git a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/isnan.ll 
b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/isnan.ll
new file mode 100644
index 0000000000000..67bb0cd8240f3
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/isnan.ll
@@ -0,0 +1,45 @@
+; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv-unknown-vulkan %s -o - | 
FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan %s -o - 
-filetype=obj | spirv-val --target-env spv1.4 %}
+
+; CHECK-DAG: %[[#float_16:]] = OpTypeFloat 16
+; CHECK-DAG: %[[#float_32:]] = OpTypeFloat 32
+; CHECK-DAG: %[[#vec4_float_16:]] = OpTypeVector %[[#float_16]] 4
+; CHECK-DAG: %[[#vec4_float_32:]] = OpTypeVector %[[#float_32]] 4
+; CHECK-DAG: %[[#bool:]] = OpTypeBool
+; CHECK-DAG: %[[#vec4_bool:]] = OpTypeVector %[[#bool]] 4
+
+define noundef i1 @isnan_half(half noundef %a) {
+entry:
+  ; CHECK: %[[#]] = OpFunction %[[#bool]] None %[[#]]
+  ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#float_16]]
+  ; CHECK: %[[#]] = OpIsNan %[[#bool]] %[[#arg0]]
+  %hlsl.isnan = call i1 @llvm.spv.isnan.f16(half %a)
+  ret i1 %hlsl.isnan
+}
+
+define noundef i1 @isnan_float(float noundef %a) {
+entry:
+  ; CHECK: %[[#]] = OpFunction %[[#bool]] None %[[#]]
+  ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#float_32]]
+  ; CHECK: %[[#]] = OpIsNan %[[#bool]] %[[#arg0]]
+  %hlsl.isnan = call i1 @llvm.spv.isnan.f32(float %a)
+  ret i1 %hlsl.isnan
+}
+
+define noundef <4 x i1> @isnan_half4(<4 x half> noundef %a) {
+entry:
+  ; CHECK: %[[#]] = OpFunction %[[#vec4_bool]] None %[[#]]
+  ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#vec4_float_16]]
+  ; CHECK: %[[#]] = OpIsNan %[[#vec4_bool]] %[[#arg0]]
+  %hlsl.isnan = call <4 x i1> @llvm.spv.isnan.v4f16(<4 x half> %a)
+  ret <4 x i1> %hlsl.isnan
+}
+
+define noundef <4 x i1> @isnan_float4(<4 x float> noundef %a) {
+entry:
+  ; CHECK: %[[#]] = OpFunction %[[#vec4_bool]] None %[[#]]
+  ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#vec4_float_32]]
+  ; CHECK: %[[#]] = OpIsNan %[[#vec4_bool]] %[[#arg0]]
+  %hlsl.isnan = call <4 x i1> @llvm.spv.isnan.v4f32(<4 x float> %a)
+  ret <4 x i1> %hlsl.isnan
+}

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to