[clang] [clang][HLSL] Add sign intrinsic part 3 (PR #101989)
Tim Gymnich via cfe-commits
cfe-commits at lists.llvm.org
Mon Sep 9 15:10:28 PDT 2024
https://github.com/tgymnich updated https://github.com/llvm/llvm-project/pull/101989
>From 6f9a5267593a3d8263aef13899b84bb3c2e7749d Mon Sep 17 00:00:00 2001
From: Tim Gymnich <tgymnich at icloud.com>
Date: Fri, 2 Aug 2024 21:40:24 +0200
Subject: [PATCH] [clang][HLSL] Add sign intrinsic part 3
---
clang/include/clang/Basic/Builtins.td | 6 +
clang/lib/CodeGen/CGBuiltin.cpp | 17 ++
clang/lib/CodeGen/CGHLSLRuntime.h | 1 +
clang/lib/Headers/hlsl/hlsl_intrinsics.h | 72 ++++++++
clang/lib/Sema/SemaHLSL.cpp | 17 ++
clang/test/CodeGenHLSL/builtins/sign.hlsl | 157 ++++++++++++++++++
clang/test/SemaHLSL/BuiltIns/sign-errors.hlsl | 16 ++
7 files changed, 286 insertions(+)
create mode 100644 clang/test/CodeGenHLSL/builtins/sign.hlsl
create mode 100644 clang/test/SemaHLSL/BuiltIns/sign-errors.hlsl
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index d9833b6559eab3..3dc04f68b3172a 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -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"];
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 0078ceb7e892af..9950c06a0b9a6b 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -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;
}
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h
index 40dcd74b7dd241..6e226808fcbaf5 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -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)
diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
index 2ac18056b0fc3d..5075cbe7d6569a 100644
--- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h
+++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
@@ -1826,5 +1826,77 @@ _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);
+_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);
+>>>>>>> af4d3b4e2b22 ([clang][HLSL] Add sign intrinsic part 3)
} // namespace hlsl
#endif //_HLSL_HLSL_INTRINSICS_H_
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 3b91303ac8cb8a..f2158226e6ca7a 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -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"
@@ -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 {
@@ -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: {
diff --git a/clang/test/CodeGenHLSL/builtins/sign.hlsl b/clang/test/CodeGenHLSL/builtins/sign.hlsl
new file mode 100644
index 00000000000000..4bb239fb009e45
--- /dev/null
+++ b/clang/test/CodeGenHLSL/builtins/sign.hlsl
@@ -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); }
diff --git a/clang/test/SemaHLSL/BuiltIns/sign-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/sign-errors.hlsl
new file mode 100644
index 00000000000000..b67725fc77e52e
--- /dev/null
+++ b/clang/test/SemaHLSL/BuiltIns/sign-errors.hlsl
@@ -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 at -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 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_sign(p1);
+ // expected-error at -1 {passing 'bool' to parameter of incompatible type 'float'}}
+}
More information about the cfe-commits
mailing list