Skip to content

Hlsl asuint16 function #132315

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 10 commits into from
Mar 21, 2025
Merged

Hlsl asuint16 function #132315

merged 10 commits into from
Mar 21, 2025

Conversation

metkarpoonam
Copy link
Contributor

Implemented the asuint16 function and added test cases for codegen, Sema, and SPIR-V backend.
fixes #99185

@llvmbot llvmbot added clang Clang issues not falling into any other category backend:X86 clang:headers Headers provided by Clang, e.g. for intrinsics HLSL HLSL Language Support backend:SPIR-V labels Mar 21, 2025
@llvmbot
Copy link
Member

llvmbot commented Mar 21, 2025

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

@llvm/pr-subscribers-backend-spir-v

Author: None (metkarpoonam)

Changes

Implemented the asuint16 function and added test cases for codegen, Sema, and SPIR-V backend.
fixes #99185


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

4 Files Affected:

  • (modified) clang/lib/Headers/hlsl/hlsl_intrinsics.h (+28)
  • (added) clang/test/CodeGenHLSL/builtins/asuint16.hlsl (+60)
  • (added) clang/test/SemaHLSL/BuiltIns/asuint16-errors.hlsl (+51)
  • (added) llvm/test/CodeGen/SPIRV/hlsl-intrinsics/asuint16.ll (+37)
diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
index a48a8e998a015..70cbed851f0f0 100644
--- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h
+++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
@@ -80,6 +80,34 @@ void asuint(double3, out uint3, out uint3);
 _HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_splitdouble)
 void asuint(double4, out uint4, out uint4);
 
+//===----------------------------------------------------------------------===//
+// asuint16 builtins
+//===----------------------------------------------------------------------===//
+
+/// \fn uint16_t asuint16(T X)
+/// \brief Interprets the bit pattern of \a X as an 16-bit unsigned integer.
+/// \param X The input value.
+#ifdef __HLSL_ENABLE_16_BIT
+
+template <typename T, int N>
+constexpr __detail::enable_if_t<__detail::is_same<int16_t, T>::value ||
+                                    __detail::is_same<uint16_t, T>::value ||
+                                    __detail::is_same<half, T>::value,
+                                vector<uint16_t, N>>
+asuint16(vector<T, N> V) {
+  return __detail::bit_cast<uint16_t, T, N>(V);
+}
+
+template <typename T>
+constexpr __detail::enable_if_t<__detail::is_same<int16_t, T>::value ||
+                                    __detail::is_same<uint16_t, T>::value ||
+                                    __detail::is_same<half, T>::value,
+                                uint16_t>
+asuint16(T F) {
+  return __detail::bit_cast<uint16_t, T>(F);
+}
+#endif
+
 //===----------------------------------------------------------------------===//
 // distance builtins
 //===----------------------------------------------------------------------===//
diff --git a/clang/test/CodeGenHLSL/builtins/asuint16.hlsl b/clang/test/CodeGenHLSL/builtins/asuint16.hlsl
new file mode 100644
index 0000000000000..0efda5f9331a9
--- /dev/null
+++ b/clang/test/CodeGenHLSL/builtins/asuint16.hlsl
@@ -0,0 +1,60 @@
+// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple dxil-pc-shadermodel6.2-library %s -fnative-half-type -emit-llvm -O1 -o - | FileCheck %s
+
+//CHECK-LABEL: define {{.*}}test_ints
+//CHECK-SAME: {{.*}}(i16 {{.*}} [[VAL:%.*]]){{.*}}
+// CHECK-NOT: bitcast
+//CHECK: entry:
+// CHECK: ret i16 [[VAL]]
+uint16_t test_int(int16_t p0)
+{
+    return asuint16(p0);
+}
+
+//CHECK-LABEL: define {{.*}}test_uint
+//CHECK-SAME: {{.*}}(i16 {{.*}} [[VAL:%.*]]){{.*}}
+//CHECK-NOT: bitcast
+//CHECK: entry:
+//CHECK-NEXT: ret i16 [[VAL]]
+uint16_t test_uint(uint16_t p0)
+{
+    return asuint16(p0);
+}
+
+//CHECK-LABEL: define {{.*}}test_half
+//CHECK-SAME: {{.*}}(half {{.*}} [[VAL:%.*]]){{.*}}
+//CHECK: [[RES:%.*]] = bitcast half [[VAL]] to i16
+//CHECK-NEXT: ret i16 [[RES]]
+uint16_t test_half(half p0)
+{
+    return asuint16(p0);
+}
+
+//CHECK-LABEL: define {{.*}}test_vector_int
+//CHECK-SAME: {{.*}}(<4 x i16> {{.*}} [[VAL:%.*]]){{.*}}
+//CHECK-NOT: bitcast
+//CHECK: entry:
+//CHECK-NEXT: ret <4 x i16> [[VAL]]
+uint16_t4 test_vector_int(int16_t4 p0)
+{
+    return asuint16(p0);
+}
+
+//CHECK-LABEL: define {{.*}}test_vector_uint
+//CHECK-SAME: {{.*}}(<4 x i16> {{.*}} [[VAL:%.*]]){{.*}}
+//CHECK-NOT: bitcast
+//CHECK: entry:
+//CHECK-NEXT: ret <4 x i16> [[VAL]]
+uint16_t4 test_vector_uint(uint16_t4 p0)
+{
+    return asuint16(p0);
+}
+
+//CHECK-LABEL: define {{.*}}fn
+//CHECK-SAME: {{.*}}(<4 x half> {{.*}} [[VAL:%.*]]){{.*}}
+//CHECK: [[RES:%.*]] = bitcast <4 x half> [[VAL]] to <4 x i16>
+//CHECK-NEXT: ret <4 x i16> [[RES]]
+uint16_t4 fn(half4 p1)
+{
+    return asuint16(p1);
+}
+
diff --git a/clang/test/SemaHLSL/BuiltIns/asuint16-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/asuint16-errors.hlsl
new file mode 100644
index 0000000000000..364eb828d81f4
--- /dev/null
+++ b/clang/test/SemaHLSL/BuiltIns/asuint16-errors.hlsl
@@ -0,0 +1,51 @@
+// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.2-library %s -fnative-half-type -verify
+
+uint16_t test_asuint16_less_argument()
+{
+    return asuint16();
+  // expected-error@-1 {{no matching function for call to 'asuint16'}}
+  // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires single argument 'V', but no arguments were provided}}
+  // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires single argument 'F', but no arguments were provided}}
+
+}
+
+int16_t4 test_asuint16_too_many_arg(uint16_t p0, uint16_t p1)
+{
+    return asuint16(p0, p1);
+  // expected-error@-1 {{no matching function for call to 'asuint16'}}
+  // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires single argument 'V', but 2 arguments were provided}}
+  // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires single argument 'F', but 2 arguments were provided}}
+
+}
+
+int16_t test_asuint16_int(int p1)
+{
+    return asuint16(p1);
+  // expected-error@-1 {{no matching function for call to 'asuint16'}}
+  // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: could not match 'vector<T, N>' against 'int'}}
+  // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with T = int]: no type named 'Type'}}
+}
+
+int16_t test_asuint16_float(float p1)
+{
+    return asuint16(p1);
+  // expected-error@-1 {{no matching function for call to 'asuint16'}}
+  // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: could not match 'vector<T, N>' against 'float'}}
+  // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with T = float]: no type named 'Type'}}
+}
+
+int16_t4 test_asuint16_vector_int(int4 p1)
+{
+    return asuint16(p1);
+  // expected-error@-1 {{no matching function for call to 'asuint16'}}
+  // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with T = int, N = 4]: no type named 'Type'}}
+  // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with T = int4]: no type named 'Type'}}
+}
+
+int16_t4 test_asuint16_vector_float(float4 p1)
+{
+    return asuint16(p1);
+  // expected-error@-1 {{no matching function for call to 'asuint16'}}
+  // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with T = float, N = 4]: no type named 'Type'}}
+  // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with T = float4]: no type named 'Type'}}
+}
diff --git a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/asuint16.ll b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/asuint16.ll
new file mode 100644
index 0000000000000..3c9e6733c1805
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/asuint16.ll
@@ -0,0 +1,37 @@
+; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+; CHECK-DAG: %[[#half:]] = OpTypeFloat 16
+; CHECK-DAG: %[[#uint_16:]] = OpTypeInt 16 0
+; CHECK-DAG: %[[#v4uint_16:]] = OpTypeVector %[[#uint_16]] 4
+; CHECK-DAG: %[[#v4half:]] = OpTypeVector %[[#half]] 4
+
+define i16 @test_half(half nofpclass(nan inf) %p0) {
+entry:
+  %0 = bitcast half %p0 to i16
+  ret i16 %0
+
+ ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#half]]
+ ; CHECK: %[[#bit_cast:]] = OpBitcast %[[#uint_16]] %[[#arg0]]
+ ; CHECK: OpReturnValue %[[#bit_cast]]
+}
+
+define noundef <4 x i16> @test_vector_half(<4 x half> nofpclass(nan inf) %p1) {
+entry:
+  %0 = bitcast <4 x half> %p1 to <4 x i16>
+  ret <4 x i16> %0
+
+ ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#v4half]]
+ ; CHECK: %[[#bit_cast:]] = OpBitcast %[[#v4uint_16]] %[[#arg0]]
+ ; CHECK: OpReturnValue %[[#bit_cast]]
+}
+
+attributes #0 = { alwaysinline mustprogress nofree norecurse nosync nounwind willreturn memory(none) "approx-func-fp-math"="true" "no-infs-fp-math"="true" "no-nans-fp-math"="true" "no-signed-zeros-fp-math"="true" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
+
+!llvm.module.flags = !{!0}
+!dx.valver = !{!1}
+!llvm.ident = !{!2}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{i32 1, i32 8}
+!2 = !{!"clang version 21.0.0git (https://github.com/llvm/llvm-project.git 8037234c865d98219b54a70d9d63aee1d1f2be1c)"}

; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}

; CHECK-DAG: %[[#half:]] = OpTypeFloat 16
Copy link
Member

Choose a reason for hiding this comment

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

delete this file. the tests you have in the asint16 pr are sufficient to for testing OpBitcast works for both scalars and vectors.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've removed the asuint16.ll as suggested.


//CHECK-LABEL: define {{.*}}test_ints
//CHECK-SAME: {{.*}}(i16 {{.*}} [[VAL:%.*]]){{.*}}
// CHECK-NOT: bitcast
Copy link
Member

@farzonl farzonl Mar 21, 2025

Choose a reason for hiding this comment

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

all the check lines in the file should line up remove space here and line 7

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've removed the spaces as suggested.

#ifdef __HLSL_ENABLE_16_BIT

template <typename T, int N>
constexpr __detail::enable_if_t<__detail::is_same<int16_t, T>::value ||
Copy link
Member

Choose a reason for hiding this comment

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

you need to add the Shader Model 6.2 availability macro to these two functions.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added suggested shader model macro.

Copy link

github-actions bot commented Mar 21, 2025

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

Copy link
Contributor

@V-FEXrt V-FEXrt left a comment

Choose a reason for hiding this comment

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

LGTM but I'll let Farzon approve

Comment on lines +25 to +26
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: could not match 'vector<T, N>' against 'int'}}
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with T = int]: no type named 'Type'}}
Copy link
Contributor

Choose a reason for hiding this comment

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

Probably not an actionable item unless @farzonl has any ideas

The notes here feel quite unhelpful from a user perspective. I'm guessing the error is that int doesn't fit in int16_t but if I was a user and I saw this error then I'd be extremely confusing by what's actually wrong. That said the actual error at least points at the function and tells you it's the wrong overload so maybe not

Copy link
Member

Choose a reason for hiding this comment

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

Since this is a language overload resolution rule and not one we defined in sema there is not much we can do in this PR. Atleast nothing that woudn't be considered scope creep. Worth talk with Chris about though and see if there is something we can change.

Copy link
Member

@farzonl farzonl left a comment

Choose a reason for hiding this comment

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

LGTM

@farzonl farzonl merged commit 5ecbf46 into llvm:main Mar 21, 2025
11 checks passed
@damyanp damyanp moved this to Closed in HLSL Support Apr 25, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:SPIR-V backend:X86 clang:headers Headers provided by Clang, e.g. for intrinsics clang Clang issues not falling into any other category HLSL HLSL Language Support
Projects
Status: Closed
Development

Successfully merging this pull request may close these issues.

Implement the asuint16 HLSL Function
4 participants