228 lines · plain
1// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -fnative-half-type -finclude-default-header -Wconversion -verify -o - -DERROR=1 %s2// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -fnative-half-type -finclude-default-header -ast-dump %s | FileCheck %s3 4// This test verifies floating point type implicit conversion ranks for overload5// resolution. In HLSL the built-in type ranks are half < float < double. This6// applies to both scalar and vector types.7 8// HLSL allows implicit truncation fo types, so it differentiates between9// promotions (converting to larger types) and conversions (converting to10// smaller types). Promotions are preferred over conversions. Promotions prefer11// promoting to the next lowest type in the ranking order. Conversions prefer12// converting to the next highest type in the ranking order.13 14void HalfFloatDouble(double D);15void HalfFloatDouble(float F);16void HalfFloatDouble(half H);17 18// CHECK: FunctionDecl {{.*}} used HalfFloatDouble 'void (double)'19// CHECK: FunctionDecl {{.*}} used HalfFloatDouble 'void (float)'20// CHECK: FunctionDecl {{.*}} used HalfFloatDouble 'void (half)'21 22void FloatDouble(double D); // expected-note{{candidate function}}23void FloatDouble(float F); // expected-note{{candidate function}}24 25// CHECK: FunctionDecl {{.*}} used FloatDouble 'void (double)'26// CHECK: FunctionDecl {{.*}} used FloatDouble 'void (float)'27 28void HalfDouble(double D);29void HalfDouble(half H);30 31// CHECK: FunctionDecl {{.*}} used HalfDouble 'void (double)'32// CHECK: FunctionDecl {{.*}} used HalfDouble 'void (half)'33 34void HalfFloat(float F); // expected-note{{candidate function}}35void HalfFloat(half H); // expected-note{{candidate function}}36 37// CHECK: FunctionDecl {{.*}} used HalfFloat 'void (float)'38// CHECK: FunctionDecl {{.*}} used HalfFloat 'void (half)'39 40void Double(double D);41void Float(float F);42void Half(half H);43 44// CHECK: FunctionDecl {{.*}} used Double 'void (double)'45// CHECK: FunctionDecl {{.*}} used Float 'void (float)'46// CHECK: FunctionDecl {{.*}} used Half 'void (half)'47 48 49// Case 1: A function declared with overloads for half float and double types.50// (a) When called with half, it will resolve to half because half is an exact51// match.52// (b) When called with float it will resolve to float because float is an53// exact match.54// (c) When called with double it will resolve to double because it is an55// exact match.56 57// CHECK-LABEL: FunctionDecl {{.*}} Case1 'void (half, float, double)'58void Case1(half H, float F, double D) {59 // CHECK: CallExpr {{.*}} 'void'60 // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(half)' <FunctionToPointerDecay>61 // CHECK-NEXT: DeclRefExpr {{.*}} 'void (half)' lvalue Function {{.*}} 'HalfFloatDouble' 'void (half)'62 HalfFloatDouble(H);63 64 // CHECK: CallExpr {{.*}} 'void'65 // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float)' <FunctionToPointerDecay>66 // CHECK-NEXT: DeclRefExpr {{.*}} 'void (float)' lvalue Function {{.*}} 'HalfFloatDouble' 'void (float)'67 HalfFloatDouble(F);68 69 // CHECK: CallExpr {{.*}} 'void'70 // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(double)' <FunctionToPointerDecay>71 // CHECK-NEXT: DeclRefExpr {{.*}} 'void (double)' lvalue Function {{.*}} 'HalfFloatDouble' 'void (double)'72 HalfFloatDouble(D);73}74 75// Case 2: A function declared with double and float overlaods.76// (a) When called with half, it will fail to resolve because it cannot77// disambiguate the promotions.78// (b) When called with float it will resolve to float because float is an79// exact match.80// (c) When called with double it will resolve to double because it is an81// exact match.82 83// CHECK-LABEL: FunctionDecl {{.*}} Case2 'void (half, float, double)'84void Case2(half H, float F, double D) {85 #if ERROR86 FloatDouble(H); // expected-error{{call to 'FloatDouble' is ambiguous}}87 #endif88 89 // CHECK: CallExpr {{.*}} 'void'90 // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float)' <FunctionToPointerDecay>91 // CHECK-NEXT: DeclRefExpr {{.*}} 'void (float)' lvalue Function {{.*}} 'FloatDouble' 'void (float)'92 FloatDouble(F);93 94 // CHECK: CallExpr {{.*}} 'void'95 // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(double)' <FunctionToPointerDecay>96 // CHECK-NEXT: DeclRefExpr {{.*}} 'void (double)' lvalue Function {{.*}} 'FloatDouble' 'void (double)'97 FloatDouble(D);98}99 100// Case 3: A function declared with half and double overloads101// (a) When called with half, it will resolve to half because it is an exact102// match.103// (b) When called with flaot, it will resolve to double because double is a104// valid promotion.105// (c) When called with double, it will resolve to double because it is an106// exact match.107 108// CHECK-LABEL: FunctionDecl {{.*}} Case3 'void (half, float, double)'109void Case3(half H, float F, double D) {110 // CHECK: CallExpr {{.*}} 'void'111 // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(half)' <FunctionToPointerDecay>112 // CHECK-NEXT: DeclRefExpr {{.*}} 'void (half)' lvalue Function {{.*}} 'HalfDouble' 'void (half)'113 HalfDouble(H);114 115 // CHECK: CallExpr {{.*}} 'void'116 // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(double)' <FunctionToPointerDecay>117 // CHECK-NEXT: DeclRefExpr {{.*}} 'void (double)' lvalue Function {{.*}} 'HalfDouble' 'void (double)'118 HalfDouble(F);119 120 // CHECK: CallExpr {{.*}} 'void'121 // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(double)' <FunctionToPointerDecay>122 // CHECK-NEXT: DeclRefExpr {{.*}} 'void (double)' lvalue Function {{.*}} 'HalfDouble' 'void (double)'123 HalfDouble(D);124}125 126// Case 4: A function declared with half and float overloads.127// (a) When called with half, it will resolve to half because half is an exact128// match.129// (b) When called with float it will resolve to float because float is an130// exact match.131// (c) When called with double it will resolve to float because it is the132// float is higher rank than half.133 134// CHECK-LABEL: FunctionDecl {{.*}} Case4 'void (half, float, double)'135void Case4(half H, float F, double D) {136 // CHECK: CallExpr {{.*}} 'void'137 // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(half)' <FunctionToPointerDecay>138 // CHECK-NEXT: DeclRefExpr {{.*}} 'void (half)' lvalue Function {{.*}} 'HalfFloat' 'void (half)'139 HalfFloat(H);140 141 // CHECK: CallExpr {{.*}} 'void'142 // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float)' <FunctionToPointerDecay>143 // CHECK-NEXT: DeclRefExpr {{.*}} 'void (float)' lvalue Function {{.*}} 'HalfFloat' 'void (float)'144 HalfFloat(F);145 146 #if ERROR147 HalfFloat(D); // expected-error{{call to 'HalfFloat' is ambiguous}}148 #endif149}150 151// Case 5: A function declared with only a double overload.152// (a) When called with half, it will resolve to double because double is a153// valid promotion.154// (b) When called with float it will resolve to double because double is a155// valid promotion.156// (c) When called with double it will resolve to double because it is an157// exact match.158 159// CHECK-LABEL: FunctionDecl {{.*}} Case5 'void (half, float, double)'160void Case5(half H, float F, double D) {161 // CHECK: CallExpr {{.*}} 'void'162 // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(double)' <FunctionToPointerDecay>163 // CHECK-NEXT: DeclRefExpr {{.*}} 'void (double)' lvalue Function {{.*}} 'Double' 'void (double)'164 Double(H);165 166 // CHECK: CallExpr {{.*}} 'void'167 // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(double)' <FunctionToPointerDecay>168 // CHECK-NEXT: DeclRefExpr {{.*}} 'void (double)' lvalue Function {{.*}} 'Double' 'void (double)'169 Double(F);170 171 // CHECK: CallExpr {{.*}} 'void'172 // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(double)' <FunctionToPointerDecay>173 // CHECK-NEXT: DeclRefExpr {{.*}} 'void (double)' lvalue Function {{.*}} 'Double' 'void (double)'174 Double(D);175}176 177// Case 6: A function declared with only a float overload.178// (a) When called with half, it will resolve to float because float is a179// valid promotion.180// (b) When called with float it will resolve to float because float is an181// exact match.182// (c) When called with double it will resolve to float because it is a183// valid conversion.184 185// CHECK-LABEL: FunctionDecl {{.*}} Case6 'void (half, float, double)'186void Case6(half H, float F, double D) {187 // CHECK: CallExpr {{.*}} 'void'188 // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float)' <FunctionToPointerDecay>189 // CHECK-NEXT: DeclRefExpr {{.*}} 'void (float)' lvalue Function {{.*}} 'Float' 'void (float)'190 Float(H);191 192 // CHECK: CallExpr {{.*}} 'void'193 // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float)' <FunctionToPointerDecay>194 // CHECK-NEXT: DeclRefExpr {{.*}} 'void (float)' lvalue Function {{.*}} 'Float' 'void (float)'195 Float(F);196 197 // CHECK: CallExpr {{.*}} 'void'198 // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float)' <FunctionToPointerDecay>199 // CHECK-NEXT: DeclRefExpr {{.*}} 'void (float)' lvalue Function {{.*}} 'Float' 'void (float)'200 Float(D); // expected-warning{{implicit conversion loses floating-point precision: 'double' to 'float'}}201}202 203// Case 7: A function declared with only a half overload.204// (a) When called with half, it will resolve to half because half is an205// exact match206// (b) When called with float it will resolve to half because half is a207// valid conversion.208// (c) When called with double it will resolve to float because it is a209// valid conversion.210 211// CHECK-LABEL: FunctionDecl {{.*}} Case7 'void (half, float, double)'212void Case7(half H, float F, double D) {213 // CHECK: CallExpr {{.*}} 'void'214 // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(half)' <FunctionToPointerDecay>215 // CHECK-NEXT: DeclRefExpr {{.*}} 'void (half)' lvalue Function {{.*}} 'Half' 'void (half)'216 Half(H);217 218 // CHECK: CallExpr {{.*}} 'void'219 // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(half)' <FunctionToPointerDecay>220 // CHECK-NEXT: DeclRefExpr {{.*}} 'void (half)' lvalue Function {{.*}} 'Half' 'void (half)'221 Half(F); // expected-warning{{implicit conversion loses floating-point precision: 'float' to 'half'}}222 223 // CHECK: CallExpr {{.*}} 'void'224 // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(half)' <FunctionToPointerDecay>225 // CHECK-NEXT: DeclRefExpr {{.*}} 'void (half)' lvalue Function {{.*}} 'Half' 'void (half)'226 Half(D); // expected-warning{{implicit conversion loses floating-point precision: 'double' to 'half'}}227}228