Skip to content

[clang][HLSL] Add sign intrinsic part 3 #101989

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 1 commit into from
Sep 10, 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 @@ -4769,6 +4769,12 @@ def HLSLSelect : LangBuiltin<"HLSL_LANG"> {
let Prototype = "void(...)";
}

def HLSLSign : LangBuiltin<"HLSL_LANG"> {
let Spellings = ["__builtin_hlsl_elementwise_sign"];
let Attributes = [NoThrow, Const];
let Prototype = "void(...)";
}

// Builtins for XRay.
def XRayCustomEvent : Builtin {
let Spellings = ["__xray_customevent"];
Expand Down
17 changes: 17 additions & 0 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18870,6 +18870,23 @@ case Builtin::BI__builtin_hlsl_elementwise_isinf: {
Intrinsic::ID ID = CGM.getHLSLRuntime().getWaveIsFirstLaneIntrinsic();
return EmitRuntimeCall(Intrinsic::getDeclaration(&CGM.getModule(), ID));
}
case Builtin::BI__builtin_hlsl_elementwise_sign: {
Value *Op0 = EmitScalarExpr(E->getArg(0));
llvm::Type *Xty = Op0->getType();
llvm::Type *retType = llvm::Type::getInt32Ty(this->getLLVMContext());
if (Xty->isVectorTy()) {
auto *XVecTy = E->getArg(0)->getType()->getAs<VectorType>();
retType = llvm::VectorType::get(
retType, ElementCount::getFixed(XVecTy->getNumElements()));
}
assert((E->getArg(0)->getType()->hasFloatingRepresentation() ||
E->getArg(0)->getType()->hasSignedIntegerRepresentation()) &&
"sign operand must have a float or int representation");

return Builder.CreateIntrinsic(
retType, CGM.getHLSLRuntime().getSignIntrinsic(),
ArrayRef<Value *>{Op0}, nullptr, "hlsl.sign");
}
}
return nullptr;
}
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 @@ -80,6 +80,7 @@ class CGHLSLRuntime {
GENERATE_HLSL_INTRINSIC_FUNCTION(Normalize, normalize)
GENERATE_HLSL_INTRINSIC_FUNCTION(Rsqrt, rsqrt)
GENERATE_HLSL_INTRINSIC_FUNCTION(Saturate, saturate)
GENERATE_HLSL_INTRINSIC_FUNCTION(Sign, sign)
GENERATE_HLSL_INTRINSIC_FUNCTION(ThreadId, thread_id)
GENERATE_HLSL_INTRINSIC_FUNCTION(FDot, fdot)
GENERATE_HLSL_INTRINSIC_FUNCTION(SDot, sdot)
Expand Down
71 changes: 71 additions & 0 deletions clang/lib/Headers/hlsl/hlsl_intrinsics.h
Original file line number Diff line number Diff line change
Expand Up @@ -1826,5 +1826,76 @@ _HLSL_AVAILABILITY(shadermodel, 6.0)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_is_first_lane)
__attribute__((convergent)) bool WaveIsFirstLane();

//===----------------------------------------------------------------------===//
// sign builtins
//===----------------------------------------------------------------------===//

/// \fn T sign(T Val)
/// \brief Returns -1 if \a Val is less than zero; 0 if \a Val equals zero; and
/// 1 if \a Val is greater than zero. \param Val The input value.

#ifdef __HLSL_ENABLE_16_BIT
_HLSL_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
int sign(int16_t);
_HLSL_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
int2 sign(int16_t2);
_HLSL_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
int3 sign(int16_t3);
_HLSL_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
int4 sign(int16_t4);
#endif

_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
int sign(half);
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
int2 sign(half2);
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
int3 sign(half3);
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
int4 sign(half4);

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
int sign(int);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@llvm-beanz the int sign(int) cases are going to have unecessary code gen. Where would be the approriate place to short-circuit that code gen to just return the input param?

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
int2 sign(int2);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
int3 sign(int3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
int4 sign(int4);

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
int sign(float);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
int2 sign(float2);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
int3 sign(float3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
int4 sign(float4);

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
int sign(int64_t);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
int2 sign(int64_t2);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
int3 sign(int64_t3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
int4 sign(int64_t4);

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
int sign(double);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
int2 sign(double2);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
int3 sign(double3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
int4 sign(double4);
} // namespace hlsl
#endif //_HLSL_HLSL_INTRINSICS_H_
17 changes: 17 additions & 0 deletions clang/lib/Sema/SemaHLSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/Type.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/DiagnosticSema.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceLocation.h"
Expand Down Expand Up @@ -1513,6 +1514,14 @@ bool CheckNoDoubleVectors(Sema *S, CallExpr *TheCall) {
return CheckArgsTypesAreCorrect(S, TheCall, S->Context.FloatTy,
checkDoubleVector);
}
bool CheckFloatingOrSignedIntRepresentation(Sema *S, CallExpr *TheCall) {
auto checkAllSignedTypes = [](clang::QualType PassedType) -> bool {
return !PassedType->hasSignedIntegerRepresentation() &&
!PassedType->hasFloatingRepresentation();
};
return CheckArgsTypesAreCorrect(S, TheCall, S->Context.IntTy,
checkAllSignedTypes);
}

bool CheckUnsignedIntRepresentation(Sema *S, CallExpr *TheCall) {
auto checkAllUnsignedTypes = [](clang::QualType PassedType) -> bool {
Expand Down Expand Up @@ -1726,6 +1735,14 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
TheCall->setType(ArgTyA);
break;
}
case Builtin::BI__builtin_hlsl_elementwise_sign: {
if (CheckFloatingOrSignedIntRepresentation(&SemaRef, TheCall))
return true;
if (SemaRef.PrepareBuiltinElementwiseMathOneArgCall(TheCall))
return true;
SetElementTypeAsReturnType(&SemaRef, TheCall, getASTContext().IntTy);
break;
}
// Note these are llvm builtins that we want to catch invalid intrinsic
// generation. Normal handling of these builitns will occur elsewhere.
case Builtin::BI__builtin_elementwise_bitreverse: {
Expand Down
157 changes: 157 additions & 0 deletions clang/test/CodeGenHLSL/builtins/sign.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
// 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: -DTARGET=dx -DFNATTRS=noundef
// 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 \
// RUN: -DTARGET=dx -DFNATTRS=noundef
// 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,NATIVE_HALF \
// RUN: -DTARGET=spv -DFNATTRS="spir_func noundef"
// 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,NO_HALF \
// RUN: -DTARGET=spv -DFNATTRS="spir_func noundef"

// NATIVE_HALF: define [[FNATTRS]] i32 @
// NATIVE_HALF: %hlsl.sign = call i32 @llvm.[[TARGET]].sign.f16(
// NATIVE_HALF: ret i32 %hlsl.sign
// NO_HALF: define [[FNATTRS]] i32 @
// NO_HALF: %hlsl.sign = call i32 @llvm.[[TARGET]].sign.f32(
// NO_HALF: ret i32 %hlsl.sign
int test_sign_half(half p0) { return sign(p0); }

// NATIVE_HALF: define [[FNATTRS]] <2 x i32> @
// NATIVE_HALF: %hlsl.sign = call <2 x i32> @llvm.[[TARGET]].sign.v2f16(
// NATIVE_HALF: ret <2 x i32> %hlsl.sign
// NO_HALF: define [[FNATTRS]] <2 x i32> @
// NO_HALF: %hlsl.sign = call <2 x i32> @llvm.[[TARGET]].sign.v2f32(
// NO_HALF: ret <2 x i32> %hlsl.sign
int2 test_sign_half2(half2 p0) { return sign(p0); }

// NATIVE_HALF: define [[FNATTRS]] <3 x i32> @
// NATIVE_HALF: %hlsl.sign = call <3 x i32> @llvm.[[TARGET]].sign.v3f16(
// NATIVE_HALF: ret <3 x i32> %hlsl.sign
// NO_HALF: define [[FNATTRS]] <3 x i32> @
// NO_HALF: %hlsl.sign = call <3 x i32> @llvm.[[TARGET]].sign.v3f32(
// NO_HALF: ret <3 x i32> %hlsl.sign
int3 test_sign_half3(half3 p0) { return sign(p0); }

// NATIVE_HALF: define [[FNATTRS]] <4 x i32> @
// NATIVE_HALF: %hlsl.sign = call <4 x i32> @llvm.[[TARGET]].sign.v4f16(
// NATIVE_HALF: ret <4 x i32> %hlsl.sign
// NO_HALF: define [[FNATTRS]] <4 x i32> @
// NO_HALF: %hlsl.sign = call <4 x i32> @llvm.[[TARGET]].sign.v4f32(
// NO_HALF: ret <4 x i32> %hlsl.sign
int4 test_sign_half4(half4 p0) { return sign(p0); }


// CHECK: define [[FNATTRS]] i32 @
// CHECK: %hlsl.sign = call i32 @llvm.[[TARGET]].sign.f32(
// CHECK: ret i32 %hlsl.sign
int test_sign_float(float p0) { return sign(p0); }

// CHECK: define [[FNATTRS]] <2 x i32> @
// CHECK: %hlsl.sign = call <2 x i32> @llvm.[[TARGET]].sign.v2f32(
// CHECK: ret <2 x i32> %hlsl.sign
int2 test_sign_float2(float2 p0) { return sign(p0); }

// CHECK: define [[FNATTRS]] <3 x i32> @
// CHECK: %hlsl.sign = call <3 x i32> @llvm.[[TARGET]].sign.v3f32(
// CHECK: ret <3 x i32> %hlsl.sign
int3 test_sign_float3(float3 p0) { return sign(p0); }

// CHECK: define [[FNATTRS]] <4 x i32> @
// CHECK: %hlsl.sign = call <4 x i32> @llvm.[[TARGET]].sign.v4f32(
// CHECK: ret <4 x i32> %hlsl.sign
int4 test_sign_float4(float4 p0) { return sign(p0); }


// CHECK: define [[FNATTRS]] i32 @
// CHECK: %hlsl.sign = call i32 @llvm.[[TARGET]].sign.f64(
// CHECK: ret i32 %hlsl.sign
int test_sign_double(double p0) { return sign(p0); }

// CHECK: define [[FNATTRS]] <2 x i32> @
// CHECK: %hlsl.sign = call <2 x i32> @llvm.[[TARGET]].sign.v2f64(
// CHECK: ret <2 x i32> %hlsl.sign
int2 test_sign_double2(double2 p0) { return sign(p0); }

// CHECK: define [[FNATTRS]] <3 x i32> @
// CHECK: %hlsl.sign = call <3 x i32> @llvm.[[TARGET]].sign.v3f64(
// CHECK: ret <3 x i32> %hlsl.sign
int3 test_sign_double3(double3 p0) { return sign(p0); }

// CHECK: define [[FNATTRS]] <4 x i32> @
// CHECK: %hlsl.sign = call <4 x i32> @llvm.[[TARGET]].sign.v4f64(
// CHECK: ret <4 x i32> %hlsl.sign
int4 test_sign_double4(double4 p0) { return sign(p0); }


#ifdef __HLSL_ENABLE_16_BIT
// NATIVE_HALF: define [[FNATTRS]] i32 @
// NATIVE_HALF: %hlsl.sign = call i32 @llvm.[[TARGET]].sign.i16(
// NATIVE_HALF: ret i32 %hlsl.sign
int test_sign_int16_t(int16_t p0) { return sign(p0); }

// NATIVE_HALF: define [[FNATTRS]] <2 x i32> @
// NATIVE_HALF: %hlsl.sign = call <2 x i32> @llvm.[[TARGET]].sign.v2i16(
// NATIVE_HALF: ret <2 x i32> %hlsl.sign
int2 test_sign_int16_t2(int16_t2 p0) { return sign(p0); }

// NATIVE_HALF: define [[FNATTRS]] <3 x i32> @
// NATIVE_HALF: %hlsl.sign = call <3 x i32> @llvm.[[TARGET]].sign.v3i16(
// NATIVE_HALF: ret <3 x i32> %hlsl.sign
int3 test_sign_int16_t3(int16_t3 p0) { return sign(p0); }

// NATIVE_HALF: define [[FNATTRS]] <4 x i32> @
// NATIVE_HALF: %hlsl.sign = call <4 x i32> @llvm.[[TARGET]].sign.v4i16(
// NATIVE_HALF: ret <4 x i32> %hlsl.sign
int4 test_sign_int16_t4(int16_t4 p0) { return sign(p0); }
#endif // __HLSL_ENABLE_16_BIT


// CHECK: define [[FNATTRS]] i32 @
// CHECK: %hlsl.sign = call i32 @llvm.[[TARGET]].sign.i32(
// CHECK: ret i32 %hlsl.sign
int test_sign_int(int p0) { return sign(p0); }

// CHECK: define [[FNATTRS]] <2 x i32> @
// CHECK: %hlsl.sign = call <2 x i32> @llvm.[[TARGET]].sign.v2i32(
// CHECK: ret <2 x i32> %hlsl.sign
int2 test_sign_int2(int2 p0) { return sign(p0); }

// CHECK: define [[FNATTRS]] <3 x i32> @
// CHECK: %hlsl.sign = call <3 x i32> @llvm.[[TARGET]].sign.v3i32(
// CHECK: ret <3 x i32> %hlsl.sign
int3 test_sign_int3(int3 p0) { return sign(p0); }

// CHECK: define [[FNATTRS]] <4 x i32> @
// CHECK: %hlsl.sign = call <4 x i32> @llvm.[[TARGET]].sign.v4i32(
// CHECK: ret <4 x i32> %hlsl.sign
int4 test_sign_int4(int4 p0) { return sign(p0); }


// CHECK: define [[FNATTRS]] i32 @
// CHECK: %hlsl.sign = call i32 @llvm.[[TARGET]].sign.i64(
// CHECK: ret i32 %hlsl.sign
int test_sign_int64_t(int64_t p0) { return sign(p0); }

// CHECK: define [[FNATTRS]] <2 x i32> @
// CHECK: %hlsl.sign = call <2 x i32> @llvm.[[TARGET]].sign.v2i64(
// CHECK: ret <2 x i32> %hlsl.sign
int2 test_sign_int64_t2(int64_t2 p0) { return sign(p0); }

// CHECK: define [[FNATTRS]] <3 x i32> @
// CHECK: %hlsl.sign = call <3 x i32> @llvm.[[TARGET]].sign.v3i64(
// CHECK: ret <3 x i32> %hlsl.sign
int3 test_sign_int64_t3(int64_t3 p0) { return sign(p0); }

// CHECK: define [[FNATTRS]] <4 x i32> @
// CHECK: %hlsl.sign = call <4 x i32> @llvm.[[TARGET]].sign.v4i64(
// CHECK: ret <4 x i32> %hlsl.sign
int4 test_sign_int64_t4(int64_t4 p0) { return sign(p0); }
16 changes: 16 additions & 0 deletions clang/test/SemaHLSL/BuiltIns/sign-errors.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -emit-llvm-only -disable-llvm-passes -verify -verify-ignore-unexpected

bool test_too_few_arg() {
return __builtin_hlsl_elementwise_sign();
// expected-error@-1 {{too few arguments to function call, expected 1, have 0}}
}

bool2 test_too_many_arg(float2 p0) {
return __builtin_hlsl_elementwise_sign(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_sign(p1);
// expected-error@-1 {passing 'bool' to parameter of incompatible type 'float'}}
}
Loading