| // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -fnative-half-type -finclude-default-header -verify -o - %s -DERROR=1 |
| // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -fnative-half-type -finclude-default-header -ast-dump %s | FileCheck %s |
| |
| // This test verifies floating point type implicit conversion ranks for overload |
| // resolution. In HLSL the built-in type ranks are half < float < double. This |
| // applies to both scalar and matrix types. |
| |
| // HLSL allows implicit truncation fo types, so it differentiates between |
| // promotions (converting to larger types) and conversions (converting to |
| // smaller types). Promotions are preferred over conversions. Promotions prefer |
| // promoting to the next lowest type in the ranking order. Conversions prefer |
| // converting to the next highest type in the ranking order. |
| |
| void HalfFloatDouble(double2x2 D); |
| void HalfFloatDouble(float2x2 F); |
| void HalfFloatDouble(half2x2 H); |
| |
| // CHECK: FunctionDecl {{.*}} used HalfFloatDouble 'void (double2x2)' |
| // CHECK: FunctionDecl {{.*}} used HalfFloatDouble 'void (float2x2)' |
| // CHECK: FunctionDecl {{.*}} used HalfFloatDouble 'void (half2x2)' |
| |
| void FloatDouble(double2x2 D); // expected-note {{candidate function}} |
| void FloatDouble(float2x2 F); // expected-note {{candidate function}} |
| |
| // CHECK: FunctionDecl {{.*}} used FloatDouble 'void (double2x2)' |
| // CHECK: FunctionDecl {{.*}} used FloatDouble 'void (float2x2)' |
| |
| void HalfDouble(double2x2 D); |
| void HalfDouble(half2x2 H); |
| |
| // CHECK: FunctionDecl {{.*}} used HalfDouble 'void (double2x2)' |
| // CHECK: FunctionDecl {{.*}} used HalfDouble 'void (half2x2)' |
| |
| void HalfFloat(float2x2 F); // expected-note {{candidate function}} |
| void HalfFloat(half2x2 H); // expected-note {{candidate function}} |
| |
| // CHECK: FunctionDecl {{.*}} used HalfFloat 'void (float2x2)' |
| // CHECK: FunctionDecl {{.*}} used HalfFloat 'void (half2x2)' |
| |
| void Double(double2x2 D); |
| void Float(float2x2 F); |
| void Half(half2x2 H); |
| |
| // CHECK: FunctionDecl {{.*}} used Double 'void (double2x2)' |
| // CHECK: FunctionDecl {{.*}} used Float 'void (float2x2)' |
| // CHECK: FunctionDecl {{.*}} used Half 'void (half2x2)' |
| |
| // Case 1: A function declared with overloads for half float and double types. |
| // (a) When called with half, it will resolve to half because half is an exact |
| // match. |
| // (b) When called with float it will resolve to float because float is an |
| // exact match. |
| // (c) When called with double it will resolve to double because it is an |
| // exact match. |
| |
| // CHECK-LABEL: FunctionDecl {{.*}} Case1 'void (half2x2, float2x2, double2x2)' |
| void Case1(half2x2 H, float2x2 F, double2x2 D) { |
| // CHECK: CallExpr {{.*}} 'void' |
| // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(half2x2)' <FunctionToPointerDecay> |
| // CHECK-NEXT: DeclRefExpr {{.*}} 'void (half2x2)' lvalue Function {{.*}} 'HalfFloatDouble' 'void (half2x2)' |
| HalfFloatDouble(H); |
| |
| // CHECK: CallExpr {{.*}} 'void' |
| // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float2x2)' <FunctionToPointerDecay> |
| // CHECK-NEXT: DeclRefExpr {{.*}} 'void (float2x2)' lvalue Function {{.*}} 'HalfFloatDouble' 'void (float2x2)' |
| HalfFloatDouble(F); |
| |
| // CHECK: CallExpr {{.*}} 'void' |
| // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(double2x2)' <FunctionToPointerDecay> |
| // CHECK-NEXT: DeclRefExpr {{.*}} 'void (double2x2)' lvalue Function {{.*}} 'HalfFloatDouble' 'void (double2x2)' |
| HalfFloatDouble(D); |
| } |
| |
| // Case 2: A function declared with double and float overlaods. |
| // (a) When called with half, it fails to resulve the ambiguous promotion. |
| // (b) When called with float it will resolve to float because float is an |
| // exact match. |
| // (c) When called with double it will resolve to double because it is an |
| // exact match. |
| |
| // CHECK-LABEL: FunctionDecl {{.*}} Case2 'void (half2x2, float2x2, double2x2)' |
| void Case2(half2x2 H, float2x2 F, double2x2 D) { |
| #if ERROR |
| FloatDouble(H); // expected-error {{call to 'FloatDouble' is ambiguous}} |
| #endif |
| |
| // CHECK: CallExpr {{.*}} 'void' |
| // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float2x2)' <FunctionToPointerDecay> |
| // CHECK-NEXT: DeclRefExpr {{.*}} 'void (float2x2)' lvalue Function {{.*}} 'FloatDouble' 'void (float2x2)' |
| FloatDouble(F); |
| |
| // CHECK: CallExpr {{.*}} 'void' |
| // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(double2x2)' <FunctionToPointerDecay> |
| // CHECK-NEXT: DeclRefExpr {{.*}} 'void (double2x2)' lvalue Function {{.*}} 'FloatDouble' 'void (double2x2)' |
| FloatDouble(D); |
| } |
| |
| // Case 3: A function declared with half and double overloads |
| // (a) When called with half, it will resolve to half because it is an exact |
| // match. |
| // (b) When called with flaot, it will resolve to double because double is a |
| // valid promotion. |
| // (c) When called with double, it will resolve to double because it is an |
| // exact match. |
| |
| // CHECK-LABEL: FunctionDecl {{.*}} Case3 'void (half2x2, float2x2, double2x2)' |
| void Case3(half2x2 H, float2x2 F, double2x2 D) { |
| // CHECK: CallExpr {{.*}} 'void' |
| // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(half2x2)' <FunctionToPointerDecay> |
| // CHECK-NEXT: DeclRefExpr {{.*}} 'void (half2x2)' lvalue Function {{.*}} 'HalfDouble' 'void (half2x2)' |
| HalfDouble(H); |
| |
| // CHECK: CallExpr {{.*}} 'void' |
| // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(double2x2)' <FunctionToPointerDecay> |
| // CHECK-NEXT: DeclRefExpr {{.*}} 'void (double2x2)' lvalue Function {{.*}} 'HalfDouble' 'void (double2x2)' |
| HalfDouble(F); |
| |
| // CHECK: CallExpr {{.*}} 'void' |
| // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(double2x2)' <FunctionToPointerDecay> |
| // CHECK-NEXT: DeclRefExpr {{.*}} 'void (double2x2)' lvalue Function {{.*}} 'HalfDouble' 'void (double2x2)' |
| HalfDouble(D); |
| } |
| |
| // Case 4: A function declared with half and float overloads. |
| // (a) When called with half, it will resolve to half because half is an exact |
| // match. |
| // (b) When called with float it will resolve to float because float is an |
| // exact match. |
| // (c) When called with double it fails to resolve the ambigjuous conversion. |
| |
| // CHECK-LABEL: FunctionDecl {{.*}} Case4 'void (half2x2, float2x2, double2x2)' |
| void Case4(half2x2 H, float2x2 F, double2x2 D) { |
| // CHECK: CallExpr {{.*}} 'void' |
| // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(half2x2)' <FunctionToPointerDecay> |
| // CHECK-NEXT: DeclRefExpr {{.*}} 'void (half2x2)' lvalue Function {{.*}} 'HalfFloat' 'void (half2x2)' |
| HalfFloat(H); |
| |
| // CHECK: CallExpr {{.*}} 'void' |
| // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float2x2)' <FunctionToPointerDecay> |
| // CHECK-NEXT: DeclRefExpr {{.*}} 'void (float2x2)' lvalue Function {{.*}} 'HalfFloat' 'void (float2x2)' |
| HalfFloat(F); |
| |
| #if ERROR |
| HalfFloat(D); // expected-error{{call to 'HalfFloat' is ambiguous}} |
| #endif |
| } |
| |
| // Case 5: A function declared with only a double overload. |
| // (a) When called with half, it will resolve to double because double is a |
| // valid promotion. |
| // (b) When called with float it will resolve to double because double is a |
| // valid promotion. |
| // (c) When called with double it will resolve to double because it is an |
| // exact match. |
| |
| // CHECK-LABEL: FunctionDecl {{.*}} Case5 'void (half2x2, float2x2, double2x2)' |
| void Case5(half2x2 H, float2x2 F, double2x2 D) { |
| // CHECK: CallExpr {{.*}} 'void' |
| // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(double2x2)' <FunctionToPointerDecay> |
| // CHECK-NEXT: DeclRefExpr {{.*}} 'void (double2x2)' lvalue Function {{.*}} 'Double' 'void (double2x2)' |
| Double(H); |
| |
| // CHECK: CallExpr {{.*}} 'void' |
| // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(double2x2)' <FunctionToPointerDecay> |
| // CHECK-NEXT: DeclRefExpr {{.*}} 'void (double2x2)' lvalue Function {{.*}} 'Double' 'void (double2x2)' |
| Double(F); |
| |
| // CHECK: CallExpr {{.*}} 'void' |
| // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(double2x2)' <FunctionToPointerDecay> |
| // CHECK-NEXT: DeclRefExpr {{.*}} 'void (double2x2)' lvalue Function {{.*}} 'Double' 'void (double2x2)' |
| Double(D); |
| } |
| |
| // Case 6: A function declared with only a float overload. |
| // (a) When called with half, it will resolve to float because float is a |
| // valid promotion. |
| // (b) When called with float it will resolve to float because float is an |
| // exact match. |
| // (c) When called with double it will resolve to float because it is a |
| // valid conversion. |
| |
| // CHECK-LABEL: FunctionDecl {{.*}} Case6 'void (half2x2, float2x2, double2x2)' |
| void Case6(half2x2 H, float2x2 F, double2x2 D) { |
| // CHECK: CallExpr {{.*}} 'void' |
| // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float2x2)' <FunctionToPointerDecay> |
| // CHECK-NEXT: DeclRefExpr {{.*}} 'void (float2x2)' lvalue Function {{.*}} 'Float' 'void (float2x2)' |
| Float(H); |
| |
| // CHECK: CallExpr {{.*}} 'void' |
| // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float2x2)' <FunctionToPointerDecay> |
| // CHECK-NEXT: DeclRefExpr {{.*}} 'void (float2x2)' lvalue Function {{.*}} 'Float' 'void (float2x2)' |
| Float(F); |
| |
| // CHECK: CallExpr {{.*}} 'void' |
| // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float2x2)' <FunctionToPointerDecay> |
| // CHECK-NEXT: DeclRefExpr {{.*}} 'void (float2x2)' lvalue Function {{.*}} 'Float' 'void (float2x2)' |
| Float(D); // TODO: See #168944. Make this an expect warning. {{implicit conversion loses floating-point precision: 'double2x2' (aka 'matrix<double, 2, 2>') to 'matrix<float, 2, 2>' (matrix of 2 'float' values)}} |
| } |
| |
| // Case 7: A function declared with only a half overload. |
| // (a) When called with half, it will resolve to half because half is an |
| // exact match |
| // (b) When called with float it will resolve to half because half is a |
| // valid conversion. |
| // (c) When called with double it will resolve to float because it is a |
| // valid conversion. |
| |
| // CHECK-LABEL: FunctionDecl {{.*}} Case7 'void (half2x2, float2x2, double2x2)' |
| void Case7(half2x2 H, float2x2 F, double2x2 D) { |
| // CHECK: CallExpr {{.*}} 'void' |
| // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(half2x2)' <FunctionToPointerDecay> |
| // CHECK-NEXT: DeclRefExpr {{.*}} 'void (half2x2)' lvalue Function {{.*}} 'Half' 'void (half2x2)' |
| Half(H); |
| |
| // CHECK: CallExpr {{.*}} 'void' |
| // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(half2x2)' <FunctionToPointerDecay> |
| // CHECK-NEXT: DeclRefExpr {{.*}} 'void (half2x2)' lvalue Function {{.*}} 'Half' 'void (half2x2)' |
| Half(F); // TODO: See #168944. Make this an expect warning. {{implicit conversion loses floating-point precision: 'float2x2' (aka 'matrix<float, 2, 2>') to 'matrix<half, 2, 2>' (matrix of 4 'half' values)}} |
| |
| // CHECK: CallExpr {{.*}} 'void' |
| // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(half2x2)' <FunctionToPointerDecay> |
| // CHECK-NEXT: DeclRefExpr {{.*}} 'void (half2x2)' lvalue Function {{.*}} 'Half' 'void (half2x2)' |
| Half(D); // TODO: See #168944. Make this an expect warning. {{implicit conversion loses floating-point precision: 'double2x2' (aka 'matrix<double, 2, 2>') to 'matrix<half, 2, 2>' (matrix of 4 'half' values)}} |
| } |
| |
| void fn3x2(float3x2) {} // expected-note{{candidate function}} |
| void fn2x2(float2x2) {} |
| void fn2x2IO(inout float2x2) {} |
| void fnI2x2IO(inout int2x2) {} |
| |
| void matOrVec(float4 F) {} // expected-note {{candidate function}} |
| void matOrVec(float2x2 F) {} // expected-note {{candidate function}} |
| |
| void matOrVec2(float3 F) {} // expected-note{{candidate function}} |
| void matOrVec2(float2x3 F) {} // expected-note{{candidate function}} |
| |
| void matOrVec3(float4x4 F) {} |
| |
| export void Case8(float2x3 f23, float4x4 f44, float3x3 f33, float3x2 f32) { |
| int2x2 i22 = f23; |
| // expected-warning@-1{{implicit conversion truncates matrix: 'float2x3' (aka 'matrix<float, 2, 3>') to 'int2x2' (aka 'matrix<int, 2, 2>')}} |
| //CHECK: VarDecl {{.*}} i22 'int2x2':'matrix<int, 2, 2>' cinit |
| //CHECK-NEXT: ImplicitCastExpr {{.*}} 'int2x2':'matrix<int, 2, 2>' <FloatingToIntegral> |
| //CHECK-NEXT: ImplicitCastExpr {{.*}} 'float2x3':'matrix<float, 2, 3>' <LValueToRValue> |
| #ifdef ERROR |
| int3x2 i32 = f23; // expected-error{{cannot initialize a variable of type 'matrix<int, 3, 2>' with an lvalue of type 'matrix<float, 2, 3>'}} |
| fn3x2(f23); // expected-error{{no matching function for call to 'fn3x2'}} |
| #endif |
| |
| fn2x2(f23); |
| // expected-warning@-1{{implicit conversion truncates matrix: 'float2x3' (aka 'matrix<float, 2, 3>') to 'matrix<float, 2, 2>'}} |
| //CHECK: DeclRefExpr {{.*}} 'void (float2x2)' lvalue Function {{.*}} 'fn2x2' 'void (float2x2)' |
| //CHECK-NEXT: ImplicitCastExpr {{.*}} 'matrix<float, 2, 2>' <HLSLMatrixTruncation> |
| //CHECK-NEXT: ImplicitCastExpr {{.*}} 'float2x3':'matrix<float, 2, 3>' <LValueToRValue> |
| |
| #ifdef ERROR |
| fn2x2IO(f23); // expected-error{{assigning to 'matrix<[2 * ...], 3>' from incompatible type 'matrix<[2 * ...], 2>'}} |
| fnI2x2IO(f23); // expected-error{{assigning to 'matrix<float, [...], 3>' from incompatible type 'matrix<int, [...], 2>'}} |
| #endif |
| |
| matOrVec(f23); |
| // expected-warning@-1{{implicit conversion truncates matrix: 'float2x3' (aka 'matrix<float, 2, 3>') to 'matrix<float, 2, 2>'}} |
| //CHECK: DeclRefExpr {{.*}} 'void (float2x2)' lvalue Function {{.*}} 'matOrVec' 'void (float2x2)' |
| //CHECK-NEXT: ImplicitCastExpr {{.*}} 'matrix<float, 2, 2>' <HLSLMatrixTruncation> |
| //CHECK-NEXT: ImplicitCastExpr {{.*}} 'float2x3':'matrix<float, 2, 3>' <LValueToRValue> |
| |
| matOrVec(f44); |
| // expected-warning@-1{{implicit conversion truncates matrix: 'float4x4' (aka 'matrix<float, 4, 4>') to 'matrix<float, 2, 2>'}} |
| //CHECK: DeclRefExpr {{.*}} 'void (float2x2)' lvalue Function {{.*}} 'matOrVec' 'void (float2x2)' |
| //CHECK-NEXT: ImplicitCastExpr {{.*}} 'matrix<float, 2, 2>' <HLSLMatrixTruncation> |
| //CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4x4':'matrix<float, 4, 4>' <LValueToRValue> |
| |
| #ifdef ERROR |
| matOrVec(2.0); // expected-error {{call to 'matOrVec' is ambiguous}} |
| #endif |
| matOrVec3(3.14); |
| //CHECK: ImplicitCastExpr {{.*}} 'float4x4':'matrix<float, 4, 4>' <HLSLAggregateSplatCast> |
| //CHECK-NEXT: FloatingLiteral {{.*}} <col:13> 'float' 3.140000e+00 |
| |
| matOrVec2(f23); |
| //CHECK: DeclRefExpr {{.*}} 'void (float2x3)' lvalue Function {{.*}} 'matOrVec2' 'void (float2x3)' |
| //CHECK-NEXT: ImplicitCastExpr {{.*}} 'float2x3':'matrix<float, 2, 3>' <LValueToRValue> |
| |
| matOrVec2(f44); |
| // expected-warning@-1{{implicit conversion truncates matrix: 'float4x4' (aka 'matrix<float, 4, 4>') to 'matrix<float, 2, 3>'}} |
| //CHECK: DeclRefExpr {{.*}} 'void (float2x3)' lvalue Function {{.*}} 'matOrVec2' 'void (float2x3)' |
| //CHECK-NEXT: ImplicitCastExpr {{.*}} 'matrix<float, 2, 3>' <HLSLMatrixTruncation> |
| //CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4x4':'matrix<float, 4, 4>' <LValueToRValue> |
| |
| matOrVec2(f33); |
| // expected-warning@-1{{implicit conversion truncates matrix: 'float3x3' (aka 'matrix<float, 3, 3>') to 'matrix<float, 2, 3>'}} |
| //CHECK: DeclRefExpr {{.*}} 'void (float2x3)' lvalue Function {{.*}} 'matOrVec2' 'void (float2x3)' |
| //CHECK-NEXT: ImplicitCastExpr {{.*}} 'matrix<float, 2, 3>' <HLSLMatrixTruncation> |
| //CHECK-NEXT: ImplicitCastExpr {{.*}} 'float3x3':'matrix<float, 3, 3>' <LValueToRValue> |
| |
| #ifdef ERROR |
| matOrVec2(f32); // expected-error{{no matching function for call to 'matOrVec2'}} |
| #endif |
| } |