[clang] [llvm] Implements isnan() HLSL intrinsic for DXIL and SPIR-V targets. (PR #157733)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 9 11:55:39 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-directx
Author: Dan Brown (danbrown-amd)
<details>
<summary>Changes</summary>
Addresses #<!-- -->99132.
---
Full diff: https://github.com/llvm/llvm-project/pull/157733.diff
14 Files Affected:
- (modified) clang/include/clang/Basic/Builtins.td (+6)
- (modified) clang/lib/CodeGen/CGHLSLBuiltins.cpp (+15)
- (modified) clang/lib/CodeGen/CGHLSLRuntime.h (+1)
- (modified) clang/lib/Headers/hlsl/hlsl_alias_intrinsics.h (+33)
- (modified) clang/lib/Headers/hlsl/hlsl_compat_overloads.h (+9)
- (modified) clang/lib/Headers/hlsl/hlsl_intrinsics.h (+37)
- (modified) clang/lib/Sema/SemaHLSL.cpp (+2-1)
- (added) clang/test/CodeGenHLSL/builtins/isnan-overloads.hlsl (+20)
- (added) clang/test/CodeGenHLSL/builtins/isnan.hlsl (+62)
- (added) clang/test/SemaHLSL/BuiltIns/isnan-errors.hlsl (+38)
- (modified) llvm/include/llvm/IR/IntrinsicsDirectX.td (+2)
- (modified) llvm/include/llvm/IR/IntrinsicsSPIRV.td (+2)
- (modified) llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp (+16)
- (added) llvm/test/CodeGen/SPIRV/hlsl-intrinsics/isnan.ll (+45)
``````````diff
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 at -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 at -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 at -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 at -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 at -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 at -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 at -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
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/157733
More information about the llvm-commits
mailing list