Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions clang/include/clang/Basic/Builtins.td
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down
15 changes: 15 additions & 0 deletions clang/lib/CodeGen/CGHLSLBuiltins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down
1 change: 1 addition & 0 deletions clang/lib/CodeGen/CGHLSLRuntime.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
33 changes: 33 additions & 0 deletions clang/lib/Headers/hlsl/hlsl_alias_intrinsics.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
//===----------------------------------------------------------------------===//
Expand Down
9 changes: 9 additions & 0 deletions clang/lib/Headers/hlsl/hlsl_compat_overloads.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
//===----------------------------------------------------------------------===//
Expand Down
37 changes: 37 additions & 0 deletions clang/lib/Headers/hlsl/hlsl_intrinsics.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
//===----------------------------------------------------------------------===//
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Sema/SemaHLSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
20 changes: 20 additions & 0 deletions clang/test/CodeGenHLSL/builtins/isnan-overloads.hlsl
Original file line number Diff line number Diff line change
@@ -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); }
62 changes: 62 additions & 0 deletions clang/test/CodeGenHLSL/builtins/isnan.hlsl
Original file line number Diff line number Diff line change
@@ -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); }
38 changes: 38 additions & 0 deletions clang/test/SemaHLSL/BuiltIns/isnan-errors.hlsl
Original file line number Diff line number Diff line change
@@ -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')}}
}
2 changes: 2 additions & 0 deletions llvm/include/llvm/IR/IntrinsicsDirectX.td
Original file line number Diff line number Diff line change
Expand Up @@ -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]>;
Expand Down
2 changes: 2 additions & 0 deletions llvm/include/llvm/IR/IntrinsicsSPIRV.td
Original file line number Diff line number Diff line change
Expand Up @@ -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]>;
Expand Down
16 changes: 16 additions & 0 deletions llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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:
Expand Down
45 changes: 45 additions & 0 deletions llvm/test/CodeGen/SPIRV/hlsl-intrinsics/isnan.ll
Original file line number Diff line number Diff line change
@@ -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
}
Loading