Skip to content

Commit ee7c118

Browse files
committed
[HLSL] Implement a header only distance intrinsic
1 parent c2bb056 commit ee7c118

File tree

4 files changed

+156
-0
lines changed

4 files changed

+156
-0
lines changed

clang/lib/Headers/hlsl/hlsl_detail.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,14 @@ namespace hlsl {
1313

1414
namespace __detail {
1515

16+
template <typename T, typename U> struct is_same {
17+
static const bool value = false;
18+
};
19+
20+
template <typename T> struct is_same<T, T> {
21+
static const bool value = true;
22+
};
23+
1624
template <bool B, typename T> struct enable_if {};
1725

1826
template <typename T> struct enable_if<true, T> {

clang/lib/Headers/hlsl/hlsl_intrinsics.h

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -871,6 +871,45 @@ float3 degrees(float3);
871871
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_degrees)
872872
float4 degrees(float4);
873873

874+
//===----------------------------------------------------------------------===//
875+
// distance builtins
876+
//===----------------------------------------------------------------------===//
877+
878+
/// \fn K distance(T X, T Y)
879+
/// \brief Returns a distance scalar between two vectors of \a X and \a Y.
880+
/// \param X The X input value.
881+
/// \param Y The Y input value.
882+
883+
template <typename T>
884+
constexpr __detail::enable_if_t<
885+
__detail::is_same<float, T>::value || __detail::is_same<half, T>::value, T>
886+
distance_impl(T X, T Y) {
887+
return __builtin_elementwise_abs(X - Y);
888+
}
889+
890+
template <typename T, int N>
891+
constexpr __detail::enable_if_t<
892+
__detail::is_same<float, T>::value || __detail::is_same<half, T>::value, T>
893+
distance_vec_impl(vector<T, N> X, vector<T, N> Y) {
894+
return __builtin_hlsl_length(X - Y);
895+
}
896+
897+
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
898+
const inline half distance(half X, half Y) { return distance_impl(X, Y); }
899+
900+
template <int N>
901+
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
902+
const inline half distance(vector<half, N> X, vector<half, N> Y) {
903+
return distance_vec_impl(X, Y);
904+
}
905+
906+
const inline float distance(float X, float Y) { return distance_impl(X, Y); }
907+
908+
template <int N>
909+
const inline float distance(vector<float, N> X, vector<float, N> Y) {
910+
return distance_vec_impl(X, Y);
911+
}
912+
874913
//===----------------------------------------------------------------------===//
875914
// dot product builtins
876915
//===----------------------------------------------------------------------===//
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
2+
// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
3+
// RUN: dxil-pc-shadermodel6.3-library %s -fnative-half-type \
4+
// RUN: -emit-llvm -O1 -o - | FileCheck %s
5+
6+
// CHECK-LABEL: define noundef half @_Z18test_distance_halfDhDh(
7+
// CHECK-SAME: half noundef [[X:%.*]], half noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
8+
// CHECK-NEXT: [[ENTRY:.*:]]
9+
// CHECK-NEXT: [[SUB_I:%.*]] = fsub half [[X]], [[Y]]
10+
// CHECK-NEXT: [[ELT_ABS_I:%.*]] = tail call noundef half @llvm.fabs.f16(half [[SUB_I]])
11+
// CHECK-NEXT: ret half [[ELT_ABS_I]]
12+
//
13+
half test_distance_half(half X, half Y) { return distance(X, Y); }
14+
15+
// CHECK-LABEL: define noundef half @_Z19test_distance_half2Dv2_DhS_(
16+
// CHECK-SAME: <2 x half> noundef [[X:%.*]], <2 x half> noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
17+
// CHECK-NEXT: [[ENTRY:.*:]]
18+
// CHECK-NEXT: [[SUB_I:%.*]] = fsub <2 x half> [[X]], [[Y]]
19+
// CHECK-NEXT: [[HLSL_LENGTH_I:%.*]] = tail call noundef half @llvm.dx.length.v2f16(<2 x half> [[SUB_I]])
20+
// CHECK-NEXT: ret half [[HLSL_LENGTH_I]]
21+
//
22+
half test_distance_half2(half2 X, half2 Y) { return distance(X, Y); }
23+
24+
// CHECK-LABEL: define noundef half @_Z19test_distance_half3Dv3_DhS_(
25+
// CHECK-SAME: <3 x half> noundef [[X:%.*]], <3 x half> noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
26+
// CHECK-NEXT: [[ENTRY:.*:]]
27+
// CHECK-NEXT: [[SUB_I:%.*]] = fsub <3 x half> [[X]], [[Y]]
28+
// CHECK-NEXT: [[HLSL_LENGTH_I:%.*]] = tail call noundef half @llvm.dx.length.v3f16(<3 x half> [[SUB_I]])
29+
// CHECK-NEXT: ret half [[HLSL_LENGTH_I]]
30+
//
31+
half test_distance_half3(half3 X, half3 Y) { return distance(X, Y); }
32+
33+
// CHECK-LABEL: define noundef half @_Z19test_distance_half4Dv4_DhS_(
34+
// CHECK-SAME: <4 x half> noundef [[X:%.*]], <4 x half> noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
35+
// CHECK-NEXT: [[ENTRY:.*:]]
36+
// CHECK-NEXT: [[SUB_I:%.*]] = fsub <4 x half> [[X]], [[Y]]
37+
// CHECK-NEXT: [[HLSL_LENGTH_I:%.*]] = tail call noundef half @llvm.dx.length.v4f16(<4 x half> [[SUB_I]])
38+
// CHECK-NEXT: ret half [[HLSL_LENGTH_I]]
39+
//
40+
half test_distance_half4(half4 X, half4 Y) { return distance(X, Y); }
41+
42+
// CHECK-LABEL: define noundef float @_Z19test_distance_floatff(
43+
// CHECK-SAME: float noundef [[X:%.*]], float noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
44+
// CHECK-NEXT: [[ENTRY:.*:]]
45+
// CHECK-NEXT: [[SUB_I:%.*]] = fsub float [[X]], [[Y]]
46+
// CHECK-NEXT: [[ELT_ABS_I:%.*]] = tail call noundef float @llvm.fabs.f32(float [[SUB_I]])
47+
// CHECK-NEXT: ret float [[ELT_ABS_I]]
48+
//
49+
float test_distance_float(float X, float Y) { return distance(X, Y); }
50+
51+
// CHECK-LABEL: define noundef float @_Z20test_distance_float2Dv2_fS_(
52+
// CHECK-SAME: <2 x float> noundef [[X:%.*]], <2 x float> noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
53+
// CHECK-NEXT: [[ENTRY:.*:]]
54+
// CHECK-NEXT: [[SUB_I:%.*]] = fsub <2 x float> [[X]], [[Y]]
55+
// CHECK-NEXT: [[HLSL_LENGTH_I:%.*]] = tail call noundef float @llvm.dx.length.v2f32(<2 x float> [[SUB_I]])
56+
// CHECK-NEXT: ret float [[HLSL_LENGTH_I]]
57+
//
58+
float test_distance_float2(float2 X, float2 Y) { return distance(X, Y); }
59+
60+
// CHECK-LABEL: define noundef float @_Z20test_distance_float3Dv3_fS_(
61+
// CHECK-SAME: <3 x float> noundef [[X:%.*]], <3 x float> noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
62+
// CHECK-NEXT: [[ENTRY:.*:]]
63+
// CHECK-NEXT: [[SUB_I:%.*]] = fsub <3 x float> [[X]], [[Y]]
64+
// CHECK-NEXT: [[HLSL_LENGTH_I:%.*]] = tail call noundef float @llvm.dx.length.v3f32(<3 x float> [[SUB_I]])
65+
// CHECK-NEXT: ret float [[HLSL_LENGTH_I]]
66+
//
67+
float test_distance_float3(float3 X, float3 Y) { return distance(X, Y); }
68+
69+
// CHECK-LABEL: define noundef float @_Z20test_distance_float4Dv4_fS_(
70+
// CHECK-SAME: <4 x float> noundef [[X:%.*]], <4 x float> noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
71+
// CHECK-NEXT: [[ENTRY:.*:]]
72+
// CHECK-NEXT: [[SUB_I:%.*]] = fsub <4 x float> [[X]], [[Y]]
73+
// CHECK-NEXT: [[HLSL_LENGTH_I:%.*]] = tail call noundef float @llvm.dx.length.v4f32(<4 x float> [[SUB_I]])
74+
// CHECK-NEXT: ret float [[HLSL_LENGTH_I]]
75+
//
76+
float test_distance_float4(float4 X, float4 Y) { return distance(X, Y); }
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -emit-llvm-only -disable-llvm-passes -verify
2+
3+
float test_no_second_arg(float2 p0) {
4+
return distance(p0);
5+
// expected-error@-1 {{no matching function for call to 'distance'}}
6+
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function not viable: requires 2 arguments, but 1 was provided}}
7+
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function not viable: requires 2 arguments, but 1 was provided}}
8+
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 2 arguments, but 1 was provided}}
9+
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 2 arguments, but 1 was provided}}
10+
}
11+
12+
float test_too_many_arg(float2 p0) {
13+
return distance(p0, p0, p0);
14+
// expected-error@-1 {{no matching function for call to 'distance'}}
15+
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function not viable: requires 2 arguments, but 3 were provided}}
16+
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function not viable: requires 2 arguments, but 3 were provided}}
17+
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 2 arguments, but 3 were provided}}
18+
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 2 arguments, but 3 were provided}}
19+
}
20+
21+
float test_double_inputs(double p0, double p1) {
22+
return distance(p0, p1);
23+
// expected-error@-1 {{call to 'distance' is ambiguous}}
24+
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function}}
25+
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function}}
26+
}
27+
28+
float test_int_inputs(int p0, int p1) {
29+
return distance(p0, p1);
30+
// expected-error@-1 {{call to 'distance' is ambiguous}}
31+
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function}}
32+
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function}}
33+
}

0 commit comments

Comments
 (0)