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

Conversation

tgymnich
Copy link
Member

@tgymnich tgymnich commented Aug 5, 2024

partially fixes #70078

Changes

  • Implemented sign clang builtin
  • Linked sign clang builtin with hlsl_intrinsics.h
  • Added sema checks for sign to CheckHLSLBuiltinFunctionCall in SemaChecking.cpp
  • Add codegen for sign to EmitHLSLBuiltinExpr in CGBuiltin.cpp
  • Add codegen tests to clang/test/CodeGenHLSL/builtins/sign.hlsl
  • Add sema tests to clang/test/SemaHLSL/BuiltIns/sign-errors.hlsl

Related PRs

Discussion

  • Should there be a usign intrinsic that handles the unsigned cases?

Copy link

github-actions bot commented Aug 5, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

@tgymnich tgymnich force-pushed the hlsl-sign-3 branch 2 times, most recently from 46723d8 to 2779b70 Compare August 5, 2024 14:46
@tgymnich tgymnich marked this pull request as ready for review August 5, 2024 14:46
@llvmbot llvmbot added clang Clang issues not falling into any other category backend:X86 clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:headers Headers provided by Clang, e.g. for intrinsics clang:codegen IR generation bugs: mangling, exceptions, etc. HLSL HLSL Language Support labels Aug 5, 2024
@llvmbot
Copy link
Member

llvmbot commented Aug 5, 2024

@llvm/pr-subscribers-backend-x86
@llvm/pr-subscribers-clang

@llvm/pr-subscribers-clang-codegen

Author: Tim Gymnich (tgymnich)

Changes

partially fixes #70078

Changes

  • Implemented sign clang builtin
  • Linked sign clang builtin with hlsl_intrinsics.h
  • Added sema checks for sign to CheckHLSLBuiltinFunctionCall in SemaChecking.cpp
  • Add codegen for sign to EmitHLSLBuiltinExpr in CGBuiltin.cpp
  • Add codegen tests to clang/test/CodeGenHLSL/builtins/sign.hlsl
  • Add sema tests to clang/test/SemaHLSL/BuiltIns/sign-errors.hlsl

Related PRs

Discussion

  • Should there be a usign intrinsic that handles the unsigned cases?

Full diff: https://github.com/llvm/llvm-project/pull/101989.diff

7 Files Affected:

  • (modified) clang/include/clang/Basic/Builtins.td (+6)
  • (modified) clang/lib/CodeGen/CGBuiltin.cpp (+17)
  • (modified) clang/lib/CodeGen/CGHLSLRuntime.h (+1)
  • (modified) clang/lib/Headers/hlsl/hlsl_intrinsics.h (+72-1)
  • (modified) clang/lib/Sema/SemaHLSL.cpp (+17)
  • (added) clang/test/CodeGenHLSL/builtins/sign.hlsl (+209)
  • (added) clang/test/SemaHLSL/BuiltIns/sign-errors.hlsl (+16)
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index b025a7681bfac..6f4da6d1ec557 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -4737,6 +4737,12 @@ def HLSLRSqrt : LangBuiltin<"HLSL_LANG"> {
   let Prototype = "void(...)";
 }
 
+def HLSLSign : LangBuiltin<"HLSL_LANG"> {
+  let Spellings = ["__builtin_hlsl_elementwise_sign"];
+  let Attributes = [NoThrow, Const];
+  let Prototype = "int(...)";
+}
+
 // 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 51d1162c6e403..41be70612a4e8 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -18662,6 +18662,23 @@ case Builtin::BI__builtin_hlsl_elementwise_isinf: {
         llvm::FunctionType::get(IntTy, {}, false), "__hlsl_wave_get_lane_index",
         {}, false, true));
   }
+  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()));
+    }
+    if (!E->getArg(0)->getType()->hasFloatingRepresentation() &&
+        !E->getArg(0)->getType()->hasSignedIntegerRepresentation())
+      llvm_unreachable("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 3f2dc0ae7b84d..0aabafc98a5b1 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -78,6 +78,7 @@ class CGHLSLRuntime {
   GENERATE_HLSL_INTRINSIC_FUNCTION(Length, length)
   GENERATE_HLSL_INTRINSIC_FUNCTION(Lerp, lerp)
   GENERATE_HLSL_INTRINSIC_FUNCTION(Rsqrt, rsqrt)
+  GENERATE_HLSL_INTRINSIC_FUNCTION(Sign, sign)
   GENERATE_HLSL_INTRINSIC_FUNCTION(ThreadId, thread_id)
 
   //===----------------------------------------------------------------------===//
diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
index e35a5262f9280..3d18b74c61917 100644
--- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h
+++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
@@ -916,7 +916,7 @@ float4 lerp(float4, float4, float4);
 /// \brief Returns the length of the specified floating-point vector.
 /// \param x [in] The vector of floats, or a scalar float.
 ///
-/// Length is based on the following formula: sqrt(x[0]^2 + x[1]^2 + �).
+/// Length is based on the following formula: sqrt(x[0]^2 + x[1]^2 + �).
 
 _HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
 _HLSL_BUILTIN_ALIAS(__builtin_hlsl_length)
@@ -1725,5 +1725,76 @@ _HLSL_AVAILABILITY(shadermodel, 6.0)
 _HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_get_lane_index)
 __attribute__((convergent)) uint WaveGetLaneIndex();
 
+//===----------------------------------------------------------------------===//
+// 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)
+int16_t sign(int16_t);
+_HLSL_AVAILABILITY(shadermodel, 6.2)
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
+int16_t2 sign(int16_t2);
+_HLSL_AVAILABILITY(shadermodel, 6.2)
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
+int16_t3 sign(int16_t3);
+_HLSL_AVAILABILITY(shadermodel, 6.2)
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
+int16_t4 sign(int16_t4);
+#endif
+
+_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
+half sign(half);
+_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
+half2 sign(half2);
+_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
+half3 sign(half3);
+_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
+half4 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)
+float sign(float);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
+float2 sign(float2);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
+float3 sign(float3);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
+float4 sign(float4);
+
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
+int64_t sign(int64_t);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
+int64_t2 sign(int64_t2);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
+int64_t3 sign(int64_t3);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
+int64_t4 sign(int64_t4);
+
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
+double sign(double);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
+double2 sign(double2);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
+double3 sign(double3);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
+double4 sign(double4);
 } // namespace hlsl
 #endif //_HLSL_HLSL_INTRINSICS_H_
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index a9c0c57e88221..49d0b0d270e27 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -12,6 +12,7 @@
 #include "clang/AST/Decl.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Basic/Builtins.h"
 #include "clang/Basic/DiagnosticSema.h"
 #include "clang/Basic/LLVM.h"
 #include "clang/Basic/TargetInfo.h"
@@ -995,6 +996,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 {
@@ -1108,6 +1117,14 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
       return true;
     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 0000000000000..61596764231ec
--- /dev/null
+++ b/clang/test/CodeGenHLSL/builtins/sign.hlsl
@@ -0,0 +1,209 @@
+// 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,DXIL_CHECK,DXIL_NATIVE_HALF,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,DXIL_CHECK,NO_HALF,DXIL_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,SPIR_CHECK,NATIVE_HALF,SPIR_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,SPIR_CHECK,NO_HALF,SPIR_NO_HALF
+
+// DXIL_NATIVE_HALF: define noundef i32 @
+// SPIR_NATIVE_HALF: define spir_func noundef i32 @
+// DXIL_NATIVE_HALF: %hlsl.sign = call i32 @llvm.dx.sign.f16(
+// SPIR_NATIVE_HALF: %hlsl.sign = call i32 @llvm.spv.sign.f16(
+// NATIVE_HALF: ret i32 %hlsl.sign
+// DXIL_NO_HALF: define noundef i32 @
+// SPIR_NO_HALF: define spir_func noundef i32 @
+// DXIL_NO_HALF: %hlsl.sign = call i32 @llvm.dx.sign.f32(
+// SPIR_NO_HALF: %hlsl.sign = call i32 @llvm.spv.sign.f32(
+// NO_HALF: ret i32 %hlsl.sign
+int test_sign_half(half p0) { return sign(p0); }
+
+// DXIL_NATIVE_HALF: define noundef <2 x i32> @
+// SPIR_NATIVE_HALF: define spir_func noundef <2 x i32> @
+// DXIL_NATIVE_HALF: %hlsl.sign = call <2 x i32> @llvm.dx.sign.v2f16(
+// SPIR_NATIVE_HALF: %hlsl.sign = call <2 x i32> @llvm.spv.sign.v2f16(
+// NATIVE_HALF: ret <2 x i32> %hlsl.sign
+// DXIL_NO_HALF: define noundef <2 x i32> @
+// SPIR_NO_HALF: define spir_func noundef <2 x i32> @
+// DXIL_NO_HALF: %hlsl.sign = call <2 x i32> @llvm.dx.sign.v2f32(
+// SPIR_NO_HALF: %hlsl.sign = call <2 x i32> @llvm.spv.sign.v2f32(
+// NO_HALF: ret <2 x i32> %hlsl.sign
+int2 test_sign_half2(half2 p0) { return sign(p0); }
+
+// DXIL_NATIVE_HALF: define noundef <3 x i32> @
+// SPIR_NATIVE_HALF: define spir_func noundef <3 x i32> @
+// DXIL_NATIVE_HALF: %hlsl.sign = call <3 x i32> @llvm.dx.sign.v3f16(
+// SPIR_NATIVE_HALF: %hlsl.sign = call <3 x i32> @llvm.spv.sign.v3f16(
+// NATIVE_HALF: ret <3 x i32> %hlsl.sign
+// DXIL_NO_HALF: define noundef <3 x i32> @
+// SPIR_NO_HALF: define spir_func noundef <3 x i32> @
+// DXIL_NO_HALF: %hlsl.sign = call <3 x i32> @llvm.dx.sign.v3f32(
+// SPIR_NO_HALF: %hlsl.sign = call <3 x i32> @llvm.spv.sign.v3f32(
+// NO_HALF: ret <3 x i32> %hlsl.sign
+int3 test_sign_half3(half3 p0) { return sign(p0); }
+
+// DXIL_NATIVE_HALF: define noundef <4 x i32> @
+// SPIR_NATIVE_HALF: define spir_func noundef <4 x i32> @
+// DXIL_NATIVE_HALF: %hlsl.sign = call <4 x i32> @llvm.dx.sign.v4f16(
+// SPIR_NATIVE_HALF: %hlsl.sign = call <4 x i32> @llvm.spv.sign.v4f16(
+// NATIVE_HALF: ret <4 x i32> %hlsl.sign
+// DXIL_NO_HALF: define noundef <4 x i32> @
+// SPIR_NO_HALF: define spir_func noundef <4 x i32> @
+// DXIL_NO_HALF: %hlsl.sign = call <4 x i32> @llvm.dx.sign.v4f32(
+// SPIR_NO_HALF: %hlsl.sign = call <4 x i32> @llvm.spv.sign.v4f32(
+// NO_HALF: ret <4 x i32> %hlsl.sign
+int4 test_sign_half4(half4 p0) { return sign(p0); }
+
+
+// DXIL_CHECK: define noundef i32 @
+// SPIR_CHECK: define spir_func noundef i32 @
+// DXIL_CHECK: %hlsl.sign = call i32 @llvm.dx.sign.f32(
+// SPIR_CHECK: %hlsl.sign = call i32 @llvm.spv.sign.f32(
+// CHECK: ret i32 %hlsl.sign
+int test_sign_float(float p0) { return sign(p0); }
+
+// DXIL_CHECK: define noundef <2 x i32> @
+// SPIR_CHECK: define spir_func noundef <2 x i32> @
+// DXIL_CHECK: %hlsl.sign = call <2 x i32> @llvm.dx.sign.v2f32(
+// SPIR_CHECK: %hlsl.sign = call <2 x i32> @llvm.spv.sign.v2f32(
+// CHECK: ret <2 x i32> %hlsl.sign
+int2 test_sign_float2(float2 p0) { return sign(p0); }
+
+// DXIL_CHECK: define noundef <3 x i32> @
+// SPIR_CHECK: define spir_func noundef <3 x i32> @
+// DXIL_CHECK: %hlsl.sign = call <3 x i32> @llvm.dx.sign.v3f32(
+// SPIR_CHECK: %hlsl.sign = call <3 x i32> @llvm.spv.sign.v3f32(
+// CHECK: ret <3 x i32> %hlsl.sign
+int3 test_sign_float3(float3 p0) { return sign(p0); }
+
+// DXIL_CHECK: define noundef <4 x i32> @
+// SPIR_CHECK: define spir_func noundef <4 x i32> @
+// DXIL_CHECK: %hlsl.sign = call <4 x i32> @llvm.dx.sign.v4f32(
+// SPIR_CHECK: %hlsl.sign = call <4 x i32> @llvm.spv.sign.v4f32(
+// CHECK: ret <4 x i32> %hlsl.sign
+int4 test_sign_float4(float4 p0) { return sign(p0); }
+
+
+// DXIL_CHECK: define noundef i32 @
+// SPIR_CHECK: define spir_func noundef i32 @
+// DXIL_CHECK: %hlsl.sign = call i32 @llvm.dx.sign.f64(
+// SPIR_CHECK: %hlsl.sign = call i32 @llvm.spv.sign.f64(
+// CHECK: ret i32 %hlsl.sign
+int test_sign_double(double p0) { return sign(p0); }
+
+// DXIL_CHECK: define noundef <2 x i32> @
+// SPIR_CHECK: define spir_func noundef <2 x i32> @
+// DXIL_CHECK: %hlsl.sign = call <2 x i32> @llvm.dx.sign.v2f64(
+// SPIR_CHECK: %hlsl.sign = call <2 x i32> @llvm.spv.sign.v2f64(
+// CHECK: ret <2 x i32> %hlsl.sign
+int2 test_sign_double2(double2 p0) { return sign(p0); }
+
+// DXIL_CHECK: define noundef <3 x i32> @
+// SPIR_CHECK: define spir_func noundef <3 x i32> @
+// DXIL_CHECK: %hlsl.sign = call <3 x i32> @llvm.dx.sign.v3f64(
+// SPIR_CHECK: %hlsl.sign = call <3 x i32> @llvm.spv.sign.v3f64(
+// CHECK: ret <3 x i32> %hlsl.sign
+int3 test_sign_double3(double3 p0) { return sign(p0); }
+
+// DXIL_CHECK: define noundef <4 x i32> @
+// SPIR_CHECK: define spir_func noundef <4 x i32> @
+// DXIL_CHECK: %hlsl.sign = call <4 x i32> @llvm.dx.sign.v4f64(
+// SPIR_CHECK: %hlsl.sign = call <4 x i32> @llvm.spv.sign.v4f64(
+// CHECK: ret <4 x i32> %hlsl.sign
+int4 test_sign_double4(double4 p0) { return sign(p0); }
+
+
+#ifdef __HLSL_ENABLE_16_BIT
+// DXIL_NATIVE_HALF: define noundef i32 @
+// SPIR_NATIVE_HALF: define spir_func noundef i32 @
+// DXIL_NATIVE_HALF: %hlsl.sign = call i32 @llvm.dx.sign.i16(
+// SPIR_NATIVE_HALF: %hlsl.sign = call i32 @llvm.spv.sign.i16(
+// NATIVE_HALF: ret i32 %hlsl.sign
+int test_sign_int16_t(int16_t p0) { return sign(p0); }
+
+// DXIL_NATIVE_HALF: define noundef <2 x i32> @
+// SPIR_NATIVE_HALF: define spir_func noundef <2 x i32> @
+// DXIL_NATIVE_HALF: %hlsl.sign = call <2 x i32> @llvm.dx.sign.v2i16(
+// SPIR_NATIVE_HALF: %hlsl.sign = call <2 x i32> @llvm.spv.sign.v2i16(
+// NATIVE_HALF: ret <2 x i32> %hlsl.sign
+int2 test_sign_int16_t2(int16_t2 p0) { return sign(p0); }
+
+// DXIL_NATIVE_HALF: define noundef <3 x i32> @
+// SPIR_NATIVE_HALF: define spir_func noundef <3 x i32> @
+// DXIL_NATIVE_HALF: %hlsl.sign = call <3 x i32> @llvm.dx.sign.v3i16(
+// SPIR_NATIVE_HALF: %hlsl.sign = call <3 x i32> @llvm.spv.sign.v3i16(
+// NATIVE_HALF: ret <3 x i32> %hlsl.sign
+int3 test_sign_int16_t3(int16_t3 p0) { return sign(p0); }
+
+// DXIL_NATIVE_HALF: define noundef <4 x i32> @
+// SPIR_NATIVE_HALF: define spir_func noundef <4 x i32> @
+// DXIL_NATIVE_HALF: %hlsl.sign = call <4 x i32> @llvm.dx.sign.v4i16(
+// SPIR_NATIVE_HALF: %hlsl.sign = call <4 x i32> @llvm.spv.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
+
+
+// DXIL_CHECK: define noundef i32 @
+// SPIR_CHECK: define spir_func noundef i32 @
+// DXIL_CHECK: %hlsl.sign = call i32 @llvm.dx.sign.i32(
+// SPIR_CHECK: %hlsl.sign = call i32 @llvm.spv.sign.i32(
+// CHECK: ret i32 %hlsl.sign
+int test_sign_int(int p0) { return sign(p0); }
+
+// DXIL_CHECK: define noundef <2 x i32> @
+// SPIR_CHECK: define spir_func noundef <2 x i32> @
+// DXIL_CHECK: %hlsl.sign = call <2 x i32> @llvm.dx.sign.v2i32(
+// SPIR_CHECK: %hlsl.sign = call <2 x i32> @llvm.spv.sign.v2i32(
+// CHECK: ret <2 x i32> %hlsl.sign
+int2 test_sign_int2(int2 p0) { return sign(p0); }
+
+// DXIL_CHECK: define noundef <3 x i32> @
+// SPIR_CHECK: define spir_func noundef <3 x i32> @
+// DXIL_CHECK: %hlsl.sign = call <3 x i32> @llvm.dx.sign.v3i32(
+// SPIR_CHECK: %hlsl.sign = call <3 x i32> @llvm.spv.sign.v3i32(
+// CHECK: ret <3 x i32> %hlsl.sign
+int3 test_sign_int3(int3 p0) { return sign(p0); }
+
+// DXIL_CHECK: define noundef <4 x i32> @
+// SPIR_CHECK: define spir_func noundef <4 x i32> @
+// DXIL_CHECK: %hlsl.sign = call <4 x i32> @llvm.dx.sign.v4i32(
+// SPIR_CHECK: %hlsl.sign = call <4 x i32> @llvm.spv.sign.v4i32(
+// CHECK: ret <4 x i32> %hlsl.sign
+int4 test_sign_int4(int4 p0) { return sign(p0); }
+
+
+// DXIL_CHECK: define noundef i32 @
+// SPIR_CHECK: define spir_func noundef i32 @
+// DXIL_CHECK: %hlsl.sign = call i32 @llvm.dx.sign.i64(
+// SPIR_CHECK: %hlsl.sign = call i32 @llvm.spv.sign.i64(
+// CHECK: ret i32 %hlsl.sign
+int test_sign_int64_t(int64_t p0) { return sign(p0); }
+
+// DXIL_CHECK: define noundef <2 x i32> @
+// SPIR_CHECK: define spir_func noundef <2 x i32> @
+// DXIL_CHECK: %hlsl.sign = call <2 x i32> @llvm.dx.sign.v2i64(
+// SPIR_CHECK: %hlsl.sign = call <2 x i32> @llvm.spv.sign.v2i64(
+// CHECK: ret <2 x i32> %hlsl.sign
+int2 test_sign_int64_t2(int64_t2 p0) { return sign(p0); }
+
+// DXIL_CHECK: define noundef <3 x i32> @
+// SPIR_CHECK: define spir_func noundef <3 x i32> @
+// DXIL_CHECK: %hlsl.sign = call <3 x i32> @llvm.dx.sign.v3i64(
+// SPIR_CHECK: %hlsl.sign = call <3 x i32> @llvm.spv.sign.v3i64(
+// CHECK: ret <3 x i32> %hlsl.sign
+int3 test_sign_int64_t3(int64_t3 p0) { return sign(p0); }
+
+// DXIL_CHECK: define noundef <4 x i32> @
+// SPIR_CHECK: define spir_func noundef <4 x i32> @
+// DXIL_CHECK: %hlsl.sign = call <4 x i32> @llvm.dx.sign.v4i64(
+// SPIR_CHECK: %hlsl.sign = call <4 x i32> @llvm.spv.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 0000000000000..b67725fc77e52
--- /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@-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'}}
+}

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?

@farzonl
Copy link
Member

farzonl commented Aug 29, 2024

@tgymnich you got approval on this PR, is there something you are waiting on?

@tgymnich
Copy link
Member Author

@farzonl This PR requires the SPIRV part (#101987) to be merged.

@farzonl
Copy link
Member

farzonl commented Aug 29, 2024

@farzonl This PR requires the SPIRV part (#101987) to be merged.

I haven't signed off on that one because I wanted input from others. I'll ping some folks.
If the pr is still sitting we can make a small change in this pr that will unblock it. Add the spirv intrinsic to this pr that should be enough to prevent a compile error.

farzonl pushed a commit that referenced this pull request Sep 5, 2024
makes progress on #70078

### Changes
- Added `int_dx_sign` intrinsic in `IntrinsicsDirectX.td`
- Added expansion for `int_dx_sign in `DXILIntrinsicExpansion.cpp`
- Added DXIL backend test case

### Related PRs
- #101987
- #101989
farzonl pushed a commit that referenced this pull request Sep 9, 2024
partially fixes #70078

### Changes
- Added `int_spv_sign` intrinsic in `IntrinsicsSPIRV.td`
- Added lowering and map to `int_spv_sign in
`SPIRVInstructionSelector.cpp`
- Added SPIR-V backend test case in
`llvm/test/CodeGen/SPIRV/hlsl-intrinsics/sign.ll`

### Related PRs
- #101988
- #101989
@farzonl
Copy link
Member

farzonl commented Sep 9, 2024

@tgymnich with part 1 and 2 merged I think we are ready for this. If you fix the conflicts in the PR i'll merge it for you.

@tgymnich
Copy link
Member Author

tgymnich commented Sep 9, 2024

@farzonl Rebased and ready to go.

@farzonl farzonl merged commit dce5039 into llvm:main Sep 10, 2024
8 checks passed
@tgymnich tgymnich deleted the hlsl-sign-3 branch October 9, 2024 19:39
farzonl pushed a commit that referenced this pull request Oct 10, 2024
- Add handling for unsigned integers to hlsl_elementwise_sign
- Use `select` instead of adding dx and spirv intrinsics for unsigned
integers as [discussed previously
](#101988 (comment))

fixes #70078

### Related PRs
- #101987
- #101988
- #101989

cc @farzonl @pow2clk @bob80905 @bogner @llvm-beanz
DanielCChen pushed a commit to DanielCChen/llvm-project that referenced this pull request Oct 16, 2024
- Add handling for unsigned integers to hlsl_elementwise_sign
- Use `select` instead of adding dx and spirv intrinsics for unsigned
integers as [discussed previously
](llvm#101988 (comment))

fixes llvm#70078

### Related PRs
- llvm#101987
- llvm#101988
- llvm#101989

cc @farzonl @pow2clk @bob80905 @bogner @llvm-beanz
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:X86 clang:codegen IR generation bugs: mangling, exceptions, etc. clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:headers Headers provided by Clang, e.g. for intrinsics clang Clang issues not falling into any other category HLSL HLSL Language Support
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

Implement the sign HLSL Function
5 participants