diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index de0cfb4e46b8b..15fcdb3ced95c 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -4572,6 +4572,12 @@ def HLSLFrac : LangBuiltin<"HLSL_LANG"> { let Prototype = "void(...)"; } +def HLSLIsinf : LangBuiltin<"HLSL_LANG"> { + let Spellings = ["__builtin_hlsl_elementwise_isinf"]; + let Attributes = [NoThrow, Const]; + let Prototype = "void(...)"; +} + def HLSLLerp : LangBuiltin<"HLSL_LANG"> { let Spellings = ["__builtin_hlsl_lerp"]; let Attributes = [NoThrow, Const]; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 0a860c687921d..b9d1a4912385e 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -18062,6 +18062,20 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, /*ReturnType=*/Op0->getType(), Intrinsic::dx_frac, ArrayRef{Op0}, nullptr, "dx.frac"); } + case Builtin::BI__builtin_hlsl_elementwise_isinf: { + 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()->getAs(); + retType = llvm::VectorType::get( + retType, ElementCount::getFixed(XVecTy->getNumElements())); + } + if (!E->getArg(0)->getType()->hasFloatingRepresentation()) + llvm_unreachable("isinf operand must have a float representation"); + return Builder.CreateIntrinsic(retType, Intrinsic::dx_isinf, + ArrayRef{Op0}, nullptr, "dx.isinf"); + } case Builtin::BI__builtin_hlsl_mad: { Value *M = EmitScalarExpr(E->getArg(0)); Value *A = EmitScalarExpr(E->getArg(1)); diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h index 3bdb0a3d68b9d..718fb9a9b35c0 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h @@ -525,6 +525,39 @@ float3 frac(float3); _HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_frac) float4 frac(float4); +//===----------------------------------------------------------------------===// +// isinf builtins +//===----------------------------------------------------------------------===// + +/// \fn T isinf(T x) +/// \brief Determines if the specified value \a x is infinite. +/// \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 +INF or -INF. Otherwise, False. + +_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_isinf) +bool isinf(half); +_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_isinf) +bool2 isinf(half2); +_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_isinf) +bool3 isinf(half3); +_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_isinf) +bool4 isinf(half4); + +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_isinf) +bool isinf(float); +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_isinf) +bool2 isinf(float2); +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_isinf) +bool3 isinf(float3); +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_isinf) +bool4 isinf(float4); + //===----------------------------------------------------------------------===// // lerp builtins //===----------------------------------------------------------------------===// diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 7ba02f6d3b793..769de5c4a8fcf 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -5268,6 +5268,15 @@ bool CheckAllArgsHaveFloatRepresentation(Sema *S, CallExpr *TheCall) { return false; } +void SetElementTypeAsReturnType(Sema *S, CallExpr *TheCall, + QualType ReturnType) { + auto *VecTyA = TheCall->getArg(0)->getType()->getAs(); + if (VecTyA) + ReturnType = S->Context.getVectorType(ReturnType, VecTyA->getNumElements(), + VectorKind::Generic); + TheCall->setType(ReturnType); +} + // Note: returning true in this case results in CheckBuiltinFunctionCall // returning an ExprError bool Sema::CheckHLSLBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { @@ -5286,6 +5295,14 @@ bool Sema::CheckHLSLBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { return true; break; } + case Builtin::BI__builtin_hlsl_elementwise_isinf: { + if (checkArgCount(*this, TheCall, 1)) + return true; + if (CheckAllArgsHaveFloatRepresentation(this, TheCall)) + return true; + SetElementTypeAsReturnType(this, TheCall, this->Context.BoolTy); + break; + } case Builtin::BI__builtin_hlsl_elementwise_rsqrt: case Builtin::BI__builtin_hlsl_elementwise_rcp: case Builtin::BI__builtin_hlsl_elementwise_frac: { diff --git a/clang/test/CodeGenHLSL/builtins/isinf.hlsl b/clang/test/CodeGenHLSL/builtins/isinf.hlsl new file mode 100644 index 0000000000000..df44fc4a91dfd --- /dev/null +++ b/clang/test/CodeGenHLSL/builtins/isinf.hlsl @@ -0,0 +1,45 @@ +// 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,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,NO_HALF + +// CHECK: define noundef i1 @ +// NATIVE_HALF: %dx.isinf = call i1 @llvm.dx.isinf.f16( +// NO_HALF: %dx.isinf = call i1 @llvm.dx.isinf.f32( +// CHECK: ret i1 %dx.isinf +bool test_isinf_half(half p0) { return isinf(p0); } +// CHECK: define noundef <2 x i1> @ +// NATIVE_HALF: %dx.isinf = call <2 x i1> @llvm.dx.isinf.v2f16 +// NO_HALF: %dx.isinf = call <2 x i1> @llvm.dx.isinf.v2f32( +// CHECK: ret <2 x i1> %dx.isinf +bool2 test_isinf_half2(half2 p0) { return isinf(p0); } +// NATIVE_HALF: define noundef <3 x i1> @ +// NATIVE_HALF: %dx.isinf = call <3 x i1> @llvm.dx.isinf.v3f16 +// NO_HALF: %dx.isinf = call <3 x i1> @llvm.dx.isinf.v3f32( +// CHECK: ret <3 x i1> %dx.isinf +bool3 test_isinf_half3(half3 p0) { return isinf(p0); } +// NATIVE_HALF: define noundef <4 x i1> @ +// NATIVE_HALF: %dx.isinf = call <4 x i1> @llvm.dx.isinf.v4f16 +// NO_HALF: %dx.isinf = call <4 x i1> @llvm.dx.isinf.v4f32( +// CHECK: ret <4 x i1> %dx.isinf +bool4 test_isinf_half4(half4 p0) { return isinf(p0); } + +// CHECK: define noundef i1 @ +// CHECK: %dx.isinf = call i1 @llvm.dx.isinf.f32( +// CHECK: ret i1 %dx.isinf +bool test_isinf_float(float p0) { return isinf(p0); } +// CHECK: define noundef <2 x i1> @ +// CHECK: %dx.isinf = call <2 x i1> @llvm.dx.isinf.v2f32 +// CHECK: ret <2 x i1> %dx.isinf +bool2 test_isinf_float2(float2 p0) { return isinf(p0); } +// CHECK: define noundef <3 x i1> @ +// CHECK: %dx.isinf = call <3 x i1> @llvm.dx.isinf.v3f32 +// CHECK: ret <3 x i1> %dx.isinf +bool3 test_isinf_float3(float3 p0) { return isinf(p0); } +// CHECK: define noundef <4 x i1> @ +// CHECK: %dx.isinf = call <4 x i1> @llvm.dx.isinf.v4f32 +// CHECK: ret <4 x i1> %dx.isinf +bool4 test_isinf_float4(float4 p0) { return isinf(p0); } diff --git a/clang/test/SemaHLSL/BuiltIns/isinf-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/isinf-errors.hlsl new file mode 100644 index 0000000000000..6c3ab743e814d --- /dev/null +++ b/clang/test/SemaHLSL/BuiltIns/isinf-errors.hlsl @@ -0,0 +1,27 @@ + +// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -emit-llvm -disable-llvm-passes -verify -verify-ignore-unexpected + +bool test_too_few_arg() { + return __builtin_hlsl_elementwise_isinf(); + // expected-error@-1 {{too few arguments to function call, expected 1, have 0}} +} + +bool2 test_too_many_arg(float2 p0) { + return __builtin_hlsl_elementwise_isinf(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_isinf(p1); + // expected-error@-1 {passing 'bool' to parameter of incompatible type 'float'}} +} + +bool builtin_isinf_int_to_float_promotion(int p1) { + return __builtin_hlsl_elementwise_isinf(p1); + // expected-error@-1 {{passing 'int' to parameter of incompatible type 'float'}} +} + +bool2 builtin_isinf_int2_to_float2_promotion(int2 p1) { + return __builtin_hlsl_elementwise_isinf(p1); + // expected-error@-1 {{passing 'int2' (aka 'vector') to parameter of incompatible type '__attribute__((__vector_size__(2 * sizeof(float)))) float' (vector of 2 'float' values)}} +} diff --git a/llvm/include/llvm/IR/IntrinsicsDirectX.td b/llvm/include/llvm/IR/IntrinsicsDirectX.td index 366dedda2b3f7..957cc8f2e15eb 100644 --- a/llvm/include/llvm/IR/IntrinsicsDirectX.td +++ b/llvm/include/llvm/IR/IntrinsicsDirectX.td @@ -29,6 +29,10 @@ def int_dx_dot : def int_dx_frac : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>]>; +def int_dx_isinf : + DefaultAttrsIntrinsic<[LLVMScalarOrSameVectorWidth<0, llvm_i1_ty>], + [llvm_anyfloat_ty]>; + def int_dx_lerp : Intrinsic<[LLVMScalarOrSameVectorWidth<0, LLVMVectorElementType<0>>], [llvm_anyvector_ty, LLVMScalarOrSameVectorWidth<0, LLVMVectorElementType<0>>,LLVMScalarOrSameVectorWidth<0, LLVMVectorElementType<0>>],