xref: /llvm-project/clang/test/SemaHLSL/VectorElementOverloadResolution.hlsl (revision d91ff3f2409a721b61b68c6a8438ea6c59323df8)
1// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -fnative-half-type -finclude-default-header -Wconversion -verify -o - %s -DERROR=1
2// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -fnative-half-type -finclude-default-header -Wno-conversion -ast-dump %s | FileCheck %s
3
4// This test verifies floating point type implicit conversion ranks for overload
5// resolution. In HLSL the built-in type ranks are half < float < double. This
6// applies to both scalar and vector types.
7
8// HLSL allows implicit truncation fo types, so it differentiates between
9// promotions (converting to larger types) and conversions (converting to
10// smaller types). Promotions are preferred over conversions. Promotions prefer
11// promoting to the next lowest type in the ranking order. Conversions prefer
12// converting to the next highest type in the ranking order.
13
14void HalfFloatDouble(double2 D);
15void HalfFloatDouble(float2 F);
16void HalfFloatDouble(half2 H);
17
18// CHECK: FunctionDecl {{.*}} used HalfFloatDouble 'void (double2)'
19// CHECK: FunctionDecl {{.*}} used HalfFloatDouble 'void (float2)'
20// CHECK: FunctionDecl {{.*}} used HalfFloatDouble 'void (half2)'
21
22void FloatDouble(double2 D); // expected-note {{candidate function}}
23void FloatDouble(float2 F); // expected-note {{candidate function}}
24
25// CHECK: FunctionDecl {{.*}} used FloatDouble 'void (double2)'
26// CHECK: FunctionDecl {{.*}} used FloatDouble 'void (float2)'
27
28void HalfDouble(double2 D);
29void HalfDouble(half2 H);
30
31// CHECK: FunctionDecl {{.*}} used HalfDouble 'void (double2)'
32// CHECK: FunctionDecl {{.*}} used HalfDouble 'void (half2)'
33
34void HalfFloat(float2 F); // expected-note {{candidate function}}
35void HalfFloat(half2 H); // expected-note {{candidate function}}
36
37// CHECK: FunctionDecl {{.*}} used HalfFloat 'void (float2)'
38// CHECK: FunctionDecl {{.*}} used HalfFloat 'void (half2)'
39
40void Double(double2 D);
41void Float(float2 F);
42void Half(half2 H);
43
44// CHECK: FunctionDecl {{.*}} used Double 'void (double2)'
45// CHECK: FunctionDecl {{.*}} used Float 'void (float2)'
46// CHECK: FunctionDecl {{.*}} used Half 'void (half2)'
47
48// Case 1: A function declared with overloads for half float and double types.
49//   (a) When called with half, it will resolve to half because half is an exact
50//   match.
51//   (b) When called with float it will resolve to float because float is an
52//   exact match.
53//   (c) When called with double it will resolve to double because it is an
54//   exact match.
55
56// CHECK-LABEL: FunctionDecl {{.*}} Case1 'void (half2, float2, double2)'
57void Case1(half2 H, float2 F, double2 D) {
58  // CHECK: CallExpr {{.*}} 'void'
59  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(half2)' <FunctionToPointerDecay>
60  // CHECK-NEXT: DeclRefExpr {{.*}} 'void (half2)' lvalue Function {{.*}} 'HalfFloatDouble' 'void (half2)'
61  HalfFloatDouble(H);
62
63  // CHECK: CallExpr {{.*}} 'void'
64  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float2)' <FunctionToPointerDecay>
65  // CHECK-NEXT: DeclRefExpr {{.*}} 'void (float2)' lvalue Function {{.*}} 'HalfFloatDouble' 'void (float2)'
66  HalfFloatDouble(F);
67
68  // CHECK: CallExpr {{.*}} 'void'
69  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(double2)' <FunctionToPointerDecay>
70  // CHECK-NEXT: DeclRefExpr {{.*}} 'void (double2)' lvalue Function {{.*}} 'HalfFloatDouble' 'void (double2)'
71  HalfFloatDouble(D);
72}
73
74// Case 2: A function declared with double and float overlaods.
75//   (a) When called with half, it fails to resulve the ambiguous promotion.
76//   (b) When called with float it will resolve to float because float is an
77//   exact match.
78//   (c) When called with double it will resolve to double because it is an
79//   exact match.
80
81// CHECK-LABEL: FunctionDecl {{.*}} Case2 'void (half2, float2, double2)'
82void Case2(half2 H, float2 F, double2 D) {
83#if ERROR
84  FloatDouble(H); // expected-error {{call to 'FloatDouble' is ambiguous}}
85#endif
86
87  // CHECK: CallExpr {{.*}} 'void'
88  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float2)' <FunctionToPointerDecay>
89  // CHECK-NEXT: DeclRefExpr {{.*}} 'void (float2)' lvalue Function {{.*}} 'FloatDouble' 'void (float2)'
90  FloatDouble(F);
91
92  // CHECK: CallExpr {{.*}} 'void'
93  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(double2)' <FunctionToPointerDecay>
94  // CHECK-NEXT: DeclRefExpr {{.*}} 'void (double2)' lvalue Function {{.*}} 'FloatDouble' 'void (double2)'
95  FloatDouble(D);
96}
97
98// Case 3: A function declared with half and double overloads
99//   (a) When called with half, it will resolve to half because it is an exact
100//   match.
101//   (b) When called with flaot, it will resolve to double because double is a
102//   valid promotion.
103//   (c) When called with double, it will resolve to double because it is an
104//   exact match.
105
106// CHECK-LABEL: FunctionDecl {{.*}} Case3 'void (half2, float2, double2)'
107void Case3(half2 H, float2 F, double2 D) {
108  // CHECK: CallExpr {{.*}} 'void'
109  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(half2)' <FunctionToPointerDecay>
110  // CHECK-NEXT: DeclRefExpr {{.*}} 'void (half2)' lvalue Function {{.*}} 'HalfDouble' 'void (half2)'
111  HalfDouble(H);
112
113  // CHECK: CallExpr {{.*}} 'void'
114  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(double2)' <FunctionToPointerDecay>
115  // CHECK-NEXT: DeclRefExpr {{.*}} 'void (double2)' lvalue Function {{.*}} 'HalfDouble' 'void (double2)'
116  HalfDouble(F);
117
118  // CHECK: CallExpr {{.*}} 'void'
119  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(double2)' <FunctionToPointerDecay>
120  // CHECK-NEXT: DeclRefExpr {{.*}} 'void (double2)' lvalue Function {{.*}} 'HalfDouble' 'void (double2)'
121  HalfDouble(D);
122}
123
124// Case 4: A function declared with half and float overloads.
125//   (a) When called with half, it will resolve to half because half is an exact
126//   match.
127//   (b) When called with float it will resolve to float because float is an
128//   exact match.
129//   (c) When called with double it fails to resolve the ambigjuous conversion.
130
131// CHECK-LABEL: FunctionDecl {{.*}} Case4 'void (half2, float2, double2)'
132void Case4(half2 H, float2 F, double2 D) {
133  // CHECK: CallExpr {{.*}} 'void'
134  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(half2)' <FunctionToPointerDecay>
135  // CHECK-NEXT: DeclRefExpr {{.*}} 'void (half2)' lvalue Function {{.*}} 'HalfFloat' 'void (half2)'
136  HalfFloat(H);
137
138  // CHECK: CallExpr {{.*}} 'void'
139  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float2)' <FunctionToPointerDecay>
140  // CHECK-NEXT: DeclRefExpr {{.*}} 'void (float2)' lvalue Function {{.*}} 'HalfFloat' 'void (float2)'
141  HalfFloat(F);
142
143#if ERROR
144  HalfFloat(D); // expected-error{{call to 'HalfFloat' is ambiguous}}
145#endif
146}
147
148// Case 5: A function declared with only a double overload.
149//   (a) When called with half, it will resolve to double because double is a
150//   valid promotion.
151//   (b) When called with float it will resolve to double because double is a
152//   valid promotion.
153//   (c) When called with double it will resolve to double because it is an
154//   exact match.
155
156// CHECK-LABEL: FunctionDecl {{.*}} Case5 'void (half2, float2, double2)'
157void Case5(half2 H, float2 F, double2 D) {
158  // CHECK: CallExpr {{.*}} 'void'
159  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(double2)' <FunctionToPointerDecay>
160  // CHECK-NEXT: DeclRefExpr {{.*}} 'void (double2)' lvalue Function {{.*}} 'Double' 'void (double2)'
161  Double(H);
162
163  // CHECK: CallExpr {{.*}} 'void'
164  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(double2)' <FunctionToPointerDecay>
165  // CHECK-NEXT: DeclRefExpr {{.*}} 'void (double2)' lvalue Function {{.*}} 'Double' 'void (double2)'
166  Double(F);
167
168  // CHECK: CallExpr {{.*}} 'void'
169  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(double2)' <FunctionToPointerDecay>
170  // CHECK-NEXT: DeclRefExpr {{.*}} 'void (double2)' lvalue Function {{.*}} 'Double' 'void (double2)'
171  Double(D);
172}
173
174// Case 6: A function declared with only a float overload.
175//   (a) When called with half, it will resolve to float because float is a
176//   valid promotion.
177//   (b) When called with float it will resolve to float because float is an
178//   exact match.
179//   (c) When called with double it will resolve to float because it is a
180//   valid conversion.
181
182// CHECK-LABEL: FunctionDecl {{.*}} Case6 'void (half2, float2, double2)'
183void Case6(half2 H, float2 F, double2 D) {
184  // CHECK: CallExpr {{.*}} 'void'
185  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float2)' <FunctionToPointerDecay>
186  // CHECK-NEXT: DeclRefExpr {{.*}} 'void (float2)' lvalue Function {{.*}} 'Float' 'void (float2)'
187  Float(H);
188
189  // CHECK: CallExpr {{.*}} 'void'
190  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float2)' <FunctionToPointerDecay>
191  // CHECK-NEXT: DeclRefExpr {{.*}} 'void (float2)' lvalue Function {{.*}} 'Float' 'void (float2)'
192  Float(F);
193
194  // CHECK: CallExpr {{.*}} 'void'
195  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float2)' <FunctionToPointerDecay>
196  // CHECK-NEXT: DeclRefExpr {{.*}} 'void (float2)' lvalue Function {{.*}} 'Float' 'void (float2)'
197  Float(D); // expected-warning{{implicit conversion loses floating-point precision: 'double2' (aka 'vector<double, 2>') to 'vector<float, 2>' (vector of 2 'float' values)}}
198}
199
200// Case 7: A function declared with only a half overload.
201//   (a) When called with half, it will resolve to half because half is an
202//   exact match
203//   (b) When called with float it will resolve to half because half is a
204//   valid conversion.
205//   (c) When called with double it will resolve to float because it is a
206//   valid conversion.
207
208// CHECK-LABEL: FunctionDecl {{.*}} Case7 'void (half2, float2, double2)'
209void Case7(half2 H, float2 F, double2 D) {
210  // CHECK: CallExpr {{.*}} 'void'
211  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(half2)' <FunctionToPointerDecay>
212  // CHECK-NEXT: DeclRefExpr {{.*}} 'void (half2)' lvalue Function {{.*}} 'Half' 'void (half2)'
213  Half(H);
214
215  // CHECK: CallExpr {{.*}} 'void'
216  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(half2)' <FunctionToPointerDecay>
217  // CHECK-NEXT: DeclRefExpr {{.*}} 'void (half2)' lvalue Function {{.*}} 'Half' 'void (half2)'
218  Half(F); // expected-warning{{implicit conversion loses floating-point precision: 'float2' (aka 'vector<float, 2>') to 'vector<half, 2>' (vector of 2 'half' values)}}
219
220  // CHECK: CallExpr {{.*}} 'void'
221  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(half2)' <FunctionToPointerDecay>
222  // CHECK-NEXT: DeclRefExpr {{.*}} 'void (half2)' lvalue Function {{.*}} 'Half' 'void (half2)'
223  Half(D); // expected-warning{{implicit conversion loses floating-point precision: 'double2' (aka 'vector<double, 2>') to 'vector<half, 2>' (vector of 2 'half' values)}}
224}
225