Skip to content

[HLSL] implement the isinf intrinsic #84927

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Mar 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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 @@ -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];
Expand Down
14 changes: 14 additions & 0 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18062,6 +18062,20 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
/*ReturnType=*/Op0->getType(), Intrinsic::dx_frac,
ArrayRef<Value *>{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<VectorType>();
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<Value *>{Op0}, nullptr, "dx.isinf");
}
case Builtin::BI__builtin_hlsl_mad: {
Value *M = EmitScalarExpr(E->getArg(0));
Value *A = EmitScalarExpr(E->getArg(1));
Expand Down
33 changes: 33 additions & 0 deletions clang/lib/Headers/hlsl/hlsl_intrinsics.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
//===----------------------------------------------------------------------===//
Expand Down
17 changes: 17 additions & 0 deletions clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<VectorType>();
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) {
Expand All @@ -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: {
Expand Down
45 changes: 45 additions & 0 deletions clang/test/CodeGenHLSL/builtins/isinf.hlsl
Original file line number Diff line number Diff line change
@@ -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); }
27 changes: 27 additions & 0 deletions clang/test/SemaHLSL/BuiltIns/isinf-errors.hlsl
Original file line number Diff line number Diff line change
@@ -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<int, 2>') to parameter of incompatible type '__attribute__((__vector_size__(2 * sizeof(float)))) float' (vector of 2 'float' values)}}
}
4 changes: 4 additions & 0 deletions llvm/include/llvm/IR/IntrinsicsDirectX.td
Original file line number Diff line number Diff line change
Expand Up @@ -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>>],
Expand Down