[clang] [HLSL] Implement D3DCOLORtoUBYTE4 intrinsic (PR #122202)

Deric Cheung via cfe-commits cfe-commits at lists.llvm.org
Thu Jan 9 11:20:04 PST 2025


https://github.com/Icohedron updated https://github.com/llvm/llvm-project/pull/122202

>From f76d5038811c72d1e185cdceeb24d5014c5c8281 Mon Sep 17 00:00:00 2001
From: Icohedron <cheung.deric at gmail.com>
Date: Thu, 9 Jan 2025 01:14:52 +0000
Subject: [PATCH 1/5] Implement D3DCOLORtoUBYTE4 intrinsic

---
 clang/lib/Headers/hlsl/hlsl_detail.h            |  8 ++++++++
 clang/lib/Headers/hlsl/hlsl_intrinsics.h        | 17 +++++++++++++++++
 .../CodeGenHLSL/builtins/D3DCOLORtoUBYTE4.hlsl  | 12 ++++++++++++
 .../BuiltIns/D3DCOLORtoUBYTE4-errors.hlsl       | 13 +++++++++++++
 4 files changed, 50 insertions(+)
 create mode 100644 clang/test/CodeGenHLSL/builtins/D3DCOLORtoUBYTE4.hlsl
 create mode 100644 clang/test/SemaHLSL/BuiltIns/D3DCOLORtoUBYTE4-errors.hlsl

diff --git a/clang/lib/Headers/hlsl/hlsl_detail.h b/clang/lib/Headers/hlsl/hlsl_detail.h
index 392075d276b188..3d78f01b6be464 100644
--- a/clang/lib/Headers/hlsl/hlsl_detail.h
+++ b/clang/lib/Headers/hlsl/hlsl_detail.h
@@ -41,6 +41,14 @@ constexpr enable_if_t<sizeof(U) == sizeof(T), U> bit_cast(T F) {
   return __builtin_bit_cast(U, F);
 }
 
+constexpr vector<uint, 4> d3d_color_to_ubyte4(vector<float, 4> V) {
+  // Use the same scaling factor used by FXC (i.e., 255.001953)
+  // Excerpt from stackoverflow discussion:
+  // "Built-in rounding, necessary because of truncation. 0.001953 * 256 = 0.5"
+  // https://stackoverflow.com/questions/52103720/why-does-d3dcolortoubyte4-multiplies-components-by-255-001953f
+  return V.zyxw * 255.001953f;
+}
+
 template <typename T>
 constexpr enable_if_t<is_same<float, T>::value || is_same<half, T>::value, T>
 length_impl(T X) {
diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
index cf287e598f76ba..1ec1038190ca53 100644
--- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h
+++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
@@ -1846,6 +1846,23 @@ half3 cross(half3, half3);
 _HLSL_BUILTIN_ALIAS(__builtin_hlsl_cross)
 float3 cross(float3, float3);
 
+//===----------------------------------------------------------------------===//
+// D3DCOLORtoUBYTE4 builtins
+//===----------------------------------------------------------------------===//
+
+/// \fn T D3DCOLORtoUBYTE4(T x)
+/// \brief Converts a floating-point, 4D vector set by a D3DCOLOR to a UBYTE4.
+/// \param x [in] The floating-point vector4 to convert.
+///
+/// The return value is the UBYTE4 representation of the \a x parameter.
+///
+/// This function swizzles and scales components of the \a x parameter. Use this
+/// function to compensate for the lack of UBYTE4 support in some hardware.
+
+constexpr vector<uint, 4> D3DCOLORtoUBYTE4(vector<float, 4> V) {
+  return __detail::d3d_color_to_ubyte4(V);
+}
+
 //===----------------------------------------------------------------------===//
 // rcp builtins
 //===----------------------------------------------------------------------===//
diff --git a/clang/test/CodeGenHLSL/builtins/D3DCOLORtoUBYTE4.hlsl b/clang/test/CodeGenHLSL/builtins/D3DCOLORtoUBYTE4.hlsl
new file mode 100644
index 00000000000000..6e48800dae6698
--- /dev/null
+++ b/clang/test/CodeGenHLSL/builtins/D3DCOLORtoUBYTE4.hlsl
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -finclude-default-header -triple \
+// RUN:   dxil-pc-shadermodel6.3-library %s -fnative-half-type \
+// RUN:   -emit-llvm -O1 -o - | FileCheck %s --check-prefixes=CHECK
+
+// CHECK-LABEL: D3DCOLORtoUBYTE4
+int4 test_D3DCOLORtoUBYTE4 ( float4 p1 ) {
+  // CHECK: %[[SCALED:.*]] = fmul <4 x float> %{{.*}}, splat (float 0x406FE01000000000)
+  // CHECK: %[[CONVERTED:.*]] = fptoui <4 x float> %[[SCALED]] to <4 x i32>
+  // CHECK: %[[SHUFFLED:.*]] = shufflevector <4 x i32> %{{.*}}, <4 x i32> poison, <4 x i32> <i32 2, i32 1, i32 0, i32 3>
+  // CHECK: ret <4 x i32> %[[SHUFFLED]]
+  return D3DCOLORtoUBYTE4 ( p1 );
+}
diff --git a/clang/test/SemaHLSL/BuiltIns/D3DCOLORtoUBYTE4-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/D3DCOLORtoUBYTE4-errors.hlsl
new file mode 100644
index 00000000000000..fb41c212bd0be3
--- /dev/null
+++ b/clang/test/SemaHLSL/BuiltIns/D3DCOLORtoUBYTE4-errors.hlsl
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -emit-llvm-only -disable-llvm-passes -verify
+
+int4 test_too_few_arg() {
+  return D3DCOLORtoUBYTE4();
+  // expected-error at -1 {{no matching function for call to 'D3DCOLORtoUBYTE4'}}
+  // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate function not viable: requires single argument 'V', but no arguments were provided}}
+}
+
+int4 test_too_many_arg(float4 v) {
+  return D3DCOLORtoUBYTE4(v, v);
+  // expected-error at -1 {{no matching function for call to 'D3DCOLORtoUBYTE4'}}
+  // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate function not viable: requires single argument 'V', but 2 arguments were provided}}
+}

>From 49e5ddf3942da0d8634da22e35f66f0b675f0744 Mon Sep 17 00:00:00 2001
From: Icohedron <cheung.deric at gmail.com>
Date: Thu, 9 Jan 2025 17:30:45 +0000
Subject: [PATCH 2/5] Add additional sema tests for D3DCOLORtoUBYTE4 for
 invalid arg types

---
 .../BuiltIns/D3DCOLORtoUBYTE4-errors.hlsl        | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/clang/test/SemaHLSL/BuiltIns/D3DCOLORtoUBYTE4-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/D3DCOLORtoUBYTE4-errors.hlsl
index fb41c212bd0be3..4edf14fe0c9bff 100644
--- a/clang/test/SemaHLSL/BuiltIns/D3DCOLORtoUBYTE4-errors.hlsl
+++ b/clang/test/SemaHLSL/BuiltIns/D3DCOLORtoUBYTE4-errors.hlsl
@@ -11,3 +11,19 @@ int4 test_too_many_arg(float4 v) {
   // expected-error at -1 {{no matching function for call to 'D3DCOLORtoUBYTE4'}}
   // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate function not viable: requires single argument 'V', but 2 arguments were provided}}
 }
+
+int4 float2_arg(float2 v) {
+    return D3DCOLORtoUBYTE4(v);
+    // expected-error at -1 {{no matching function for call to 'D3DCOLORtoUBYTE4'}}
+    // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate function not viable: no known conversion from 'vector<[...], 2>' to 'vector<[...], 4>' for 1st argument}}
+}
+
+struct S {
+  float4 f;
+};
+
+int4 float2_arg(S v) {
+    return D3DCOLORtoUBYTE4(v);
+    // expected-error at -1 {{no matching function for call to 'D3DCOLORtoUBYTE4'}}
+    // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate function not viable: no known conversion from 'S' to 'vector<float, 4>' (vector of 4 'float' values) for 1st argument}}
+}

>From 506e89c5a7ed896c9e827649154a9a8dea7583f0 Mon Sep 17 00:00:00 2001
From: Icohedron <cheung.deric at gmail.com>
Date: Thu, 9 Jan 2025 18:00:39 +0000
Subject: [PATCH 3/5] Remove unnecessary whitespace

---
 clang/test/CodeGenHLSL/builtins/D3DCOLORtoUBYTE4.hlsl | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/test/CodeGenHLSL/builtins/D3DCOLORtoUBYTE4.hlsl b/clang/test/CodeGenHLSL/builtins/D3DCOLORtoUBYTE4.hlsl
index 6e48800dae6698..2af50d0accd15e 100644
--- a/clang/test/CodeGenHLSL/builtins/D3DCOLORtoUBYTE4.hlsl
+++ b/clang/test/CodeGenHLSL/builtins/D3DCOLORtoUBYTE4.hlsl
@@ -3,10 +3,10 @@
 // RUN:   -emit-llvm -O1 -o - | FileCheck %s --check-prefixes=CHECK
 
 // CHECK-LABEL: D3DCOLORtoUBYTE4
-int4 test_D3DCOLORtoUBYTE4 ( float4 p1 ) {
+int4 test_D3DCOLORtoUBYTE4(float4 p1) {
   // CHECK: %[[SCALED:.*]] = fmul <4 x float> %{{.*}}, splat (float 0x406FE01000000000)
   // CHECK: %[[CONVERTED:.*]] = fptoui <4 x float> %[[SCALED]] to <4 x i32>
   // CHECK: %[[SHUFFLED:.*]] = shufflevector <4 x i32> %{{.*}}, <4 x i32> poison, <4 x i32> <i32 2, i32 1, i32 0, i32 3>
   // CHECK: ret <4 x i32> %[[SHUFFLED]]
-  return D3DCOLORtoUBYTE4 ( p1 );
+  return D3DCOLORtoUBYTE4(p1);
 }

>From 62d5978c150b8dc36a4f745c79b6b09c816cab09 Mon Sep 17 00:00:00 2001
From: Icohedron <cheung.deric at gmail.com>
Date: Thu, 9 Jan 2025 18:13:27 +0000
Subject: [PATCH 4/5] Rename struct arg test

---
 clang/test/SemaHLSL/BuiltIns/D3DCOLORtoUBYTE4-errors.hlsl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/test/SemaHLSL/BuiltIns/D3DCOLORtoUBYTE4-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/D3DCOLORtoUBYTE4-errors.hlsl
index 4edf14fe0c9bff..e9ba851007c941 100644
--- a/clang/test/SemaHLSL/BuiltIns/D3DCOLORtoUBYTE4-errors.hlsl
+++ b/clang/test/SemaHLSL/BuiltIns/D3DCOLORtoUBYTE4-errors.hlsl
@@ -22,7 +22,7 @@ struct S {
   float4 f;
 };
 
-int4 float2_arg(S v) {
+int4 struct_arg(S v) {
     return D3DCOLORtoUBYTE4(v);
     // expected-error at -1 {{no matching function for call to 'D3DCOLORtoUBYTE4'}}
     // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate function not viable: no known conversion from 'S' to 'vector<float, 4>' (vector of 4 'float' values) for 1st argument}}

>From a4bbeda2a4c1a78e3070dda43d7b613d3792299b Mon Sep 17 00:00:00 2001
From: Icohedron <cheung.deric at gmail.com>
Date: Thu, 9 Jan 2025 19:18:00 +0000
Subject: [PATCH 5/5] Capture fast-math flags in D3DCOLORtoUBYTE4 codegen test

---
 clang/test/CodeGenHLSL/builtins/D3DCOLORtoUBYTE4.hlsl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/test/CodeGenHLSL/builtins/D3DCOLORtoUBYTE4.hlsl b/clang/test/CodeGenHLSL/builtins/D3DCOLORtoUBYTE4.hlsl
index 2af50d0accd15e..7021de7192b5e5 100644
--- a/clang/test/CodeGenHLSL/builtins/D3DCOLORtoUBYTE4.hlsl
+++ b/clang/test/CodeGenHLSL/builtins/D3DCOLORtoUBYTE4.hlsl
@@ -4,7 +4,7 @@
 
 // CHECK-LABEL: D3DCOLORtoUBYTE4
 int4 test_D3DCOLORtoUBYTE4(float4 p1) {
-  // CHECK: %[[SCALED:.*]] = fmul <4 x float> %{{.*}}, splat (float 0x406FE01000000000)
+  // CHECK: %[[SCALED:.*]] = fmul [[FMFLAGS:.*]]<4 x float> %{{.*}}, splat (float 0x406FE01000000000)
   // CHECK: %[[CONVERTED:.*]] = fptoui <4 x float> %[[SCALED]] to <4 x i32>
   // CHECK: %[[SHUFFLED:.*]] = shufflevector <4 x i32> %{{.*}}, <4 x i32> poison, <4 x i32> <i32 2, i32 1, i32 0, i32 3>
   // CHECK: ret <4 x i32> %[[SHUFFLED]]



More information about the cfe-commits mailing list