xref: /llvm-project/clang/test/SemaHLSL/Language/TemplateOutArg.hlsl (revision 89fb8490a99e612f7a574e8678b21a90f689f5b4)
1// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -finclude-default-header %s -ast-dump | FileCheck %s
2
3// Case 1: Template declaration with a call to an inout or out argument that is
4// resolved based on the template parameter. For this case the template decl
5// should have an UnresolvedLookupExpr for the call, and the HLSLOutArgExpr is
6// built during call resolution.
7
8// CHECK: FunctionDecl {{.*}} used fn 'void (inout int)'
9void fn(inout int I) {
10  I += 1;
11}
12
13// CHECK: FunctionDecl {{.*}} used fn 'void (out double)'
14void fn(out double F) {
15  F = 1.5;
16}
17
18// CHECK-LABEL: FunctionTemplateDecl {{.*}} wrapper
19// CHECK-NEXT: TemplateTypeParmDecl {{.*}} referenced typename depth 0 index 0 T
20
21// Verify that the template has an unresolved call.
22// CHECK-NEXT: FunctionDecl {{.*}} wrapper 'T (T)'
23// CHECK-NEXT: ParmVarDecl {{.*}} referenced V 'T'
24// CHECK: CallExpr {{.*}} '<dependent type>'
25// CHECK: UnresolvedLookupExpr {{.*}} '<overloaded function type>' lvalue (ADL) = 'fn'
26
27// Verify that the int instantiation resolves an inout argument expression.
28
29// CHECK-LABEL: FunctionDecl {{.*}} used wrapper 'int (int)' implicit_instantiation
30// CHECK: CallExpr {{.*}} 'void'
31// CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(inout int)' <FunctionToPointerDecay>
32// CHECK-NEXT:   DeclRefExpr {{.*}} 'void (inout int)' lvalue Function {{.*}} 'fn' 'void (inout int)'
33// CHECK-NEXT: HLSLOutArgExpr {{.*}} 'int' lvalue inout
34
35// CHECK-NEXT: OpaqueValueExpr [[LVOpV:0x[0-9a-fA-F]+]] {{.*}} 'int' lvalue
36// CHECK-NEXT: DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'V' 'int'
37// CHECK-NEXT: OpaqueValueExpr [[TmpOpV:0x[0-9a-fA-F]+]] {{.*}} 'int' lvalue
38// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
39// CHECK-NEXT: OpaqueValueExpr [[LVOpV]] {{.*}} 'int' lvalue
40
41// CHECK: BinaryOperator {{.*}} 'int' lvalue '='
42// CHECK-NEXT: OpaqueValueExpr [[LVOpV]] {{.*}} 'int' lvalue
43// CHECK: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
44// CHECK-NEXT: OpaqueValueExpr [[TmpOpV]] {{.*}} 'int' lvalue
45
46
47// Verify that the float instantiation has an out argument expression
48// containing casts to and from double.
49
50// CHECK-LABEL: FunctionDecl {{.*}} used wrapper 'float (float)' implicit_instantiation
51// CHECK: CallExpr {{.*}} 'void'
52// CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(out double)' <FunctionToPointerDecay>
53// CHECK-NEXT:   DeclRefExpr {{.*}}'void (out double)' lvalue Function {{.*}} 'fn' 'void (out double)'
54// CHECK-NEXT: HLSLOutArgExpr {{.*}} 'double' lvalue out
55// CHECK-NEXT: OpaqueValueExpr [[LVOpV:0x[0-9a-fA-F]+]] {{.*}} 'float' lvalue
56// CHECK-NEXT: DeclRefExpr {{.*}} 'float' lvalue ParmVar {{.*}} 'V' 'float'
57// CHECK-NEXT: OpaqueValueExpr [[TmpOpV:0x[0-9a-fA-F]+]] {{.*}} 'double' lvalue
58// CHECK-NEXT: ImplicitCastExpr {{.*}} 'double' <FloatingCast>
59// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
60// CHECK-NEXT: OpaqueValueExpr [[LVOpV]] {{.*}} 'float' lvalue
61
62// CHECK: BinaryOperator {{.*}} 'float' lvalue '='
63// CHECK-NEXT: OpaqueValueExpr [[LVOpV]] {{.*}} 'float' lvalue
64// CHECK: ImplicitCastExpr {{.*}} 'float' <FloatingCast>
65// CHECK-NEXT: ImplicitCastExpr {{.*}} 'double' <LValueToRValue>
66// CHECK-NEXT: OpaqueValueExpr [[TmpOpV]] {{.*}} 'double' lvalue
67
68
69// Verify that the double instantiation is just an out expression.
70
71// CHECK-LABEL: FunctionDecl {{.*}} used wrapper 'double (double)' implicit_instantiation
72// CHECK: CallExpr {{.*}} 'void'
73// CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(out double)' <FunctionToPointerDecay>
74// CHECK-NEXT:   DeclRefExpr {{.*}}'void (out double)' lvalue Function {{.*}} 'fn' 'void (out double)'
75// CHECK-NEXT: HLSLOutArgExpr {{.*}} 'double' lvalue out
76// CHECK-NEXT: OpaqueValueExpr [[LVOpV:0x[0-9a-fA-F]+]] {{.*}} 'double' lvalue
77// CHECK-NEXT: DeclRefExpr {{.*}} 'double' lvalue ParmVar {{.*}} 'V' 'double'
78// CHECK-NEXT: OpaqueValueExpr [[TmpOpV:0x[0-9a-fA-F]+]] {{.*}} 'double' lvalue
79// CHECK-NEXT: ImplicitCastExpr {{.*}} 'double' <LValueToRValue>
80// CHECK-NEXT: OpaqueValueExpr [[LVOpV]] {{.*}} 'double' lvalue
81
82// CHECK: BinaryOperator {{.*}} 'double' lvalue '='
83// CHECK-NEXT: OpaqueValueExpr [[LVOpV]] {{.*}} 'double' lvalue
84// CHECK: ImplicitCastExpr {{.*}} 'double' <LValueToRValue>
85// CHECK-NEXT: OpaqueValueExpr [[TmpOpV]] {{.*}} 'double' lvalue
86
87template <typename T>
88T wrapper(T V) {
89  fn(V);
90  return V;
91}
92
93// Case 2: Verify that the parameter modifier attribute is instantiated with the
94// template (this one is a gimme).
95
96// CHECK-LABEL: FunctionTemplateDecl {{.*}} fizz
97
98// Check the pattern decl.
99// CHECK: FunctionDecl {{.*}} fizz 'void (inout T)'
100// CHECK-NEXT: ParmVarDecl {{.*}} referenced V 'T'
101// CHECK-NEXT: HLSLParamModifierAttr {{.*}} inout
102
103// Check the 3 instantiations (int, float, & double).
104
105// CHECK-LABEL: FunctionDecl {{.*}} used fizz 'void (inout int)' implicit_instantiation
106// CHECK: ParmVarDecl {{.*}} used V 'int &__restrict'
107// CHECK-NEXT: HLSLParamModifierAttr {{.*}} inout
108
109// CHECK-LABEL: FunctionDecl {{.*}} used fizz 'void (inout float)' implicit_instantiation
110// CHECK: ParmVarDecl {{.*}} used V 'float &__restrict'
111// CHECK-NEXT: HLSLParamModifierAttr {{.*}} inout
112
113// CHECK-LABEL: FunctionDecl {{.*}} used fizz 'void (inout double)' implicit_instantiation
114// CHECK: ParmVarDecl {{.*}} used V 'double &__restrict'
115// CHECK-NEXT: HLSLParamModifierAttr {{.*}} inout
116template <typename T>
117void fizz(inout T V) {
118  V += 2;
119}
120
121// Case 3: Verify that HLSLOutArgExpr nodes which are present in the template
122// are correctly instantiated into the instantation.
123
124// First we check that the AST node is in the template.
125
126// CHECK-LABEL: FunctionTemplateDecl {{.*}} buzz
127
128// CHECK: FunctionDecl {{.*}} buzz 'T (int, T)'
129// CHECK: CallExpr {{.*}} 'void'
130// CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(inout int)' <FunctionToPointerDecay>
131// CHECK-NEXT:   DeclRefExpr {{.*}} 'void (inout int)' lvalue Function {{.*}} 'fn' 'void (inout int)'
132// CHECK-NEXT: HLSLOutArgExpr {{.*}} 'int' lvalue inout
133// CHECK-NEXT: OpaqueValueExpr [[LVOpV:0x[0-9a-fA-F]+]] {{.*}} 'int' lvalue
134// CHECK-NEXT:   DeclRefExpr  {{.*}} 'int' lvalue ParmVar {{.*}} 'X' 'int'
135// CHECK-NEXT: OpaqueValueExpr [[TmpOpV:0x[0-9a-fA-F]+]] {{.*}} 'int' lvalue
136// CHECK-NEXT:   ImplicitCastExpr  {{.*}} 'int' <LValueToRValue>
137// CHECK-NEXT:     OpaqueValueExpr [[LVOpV]] {{.*}} 'int' lvalue
138// CHECK:      BinaryOperator {{.*}} 'int' lvalue '='
139// CHECK-NEXT:   OpaqueValueExpr [[LVOpV]] {{.*}} 'int' lvalue
140// CHECK:      ImplicitCastExpr  {{.*}} 'int' <LValueToRValue>
141// CHECK-NEXT:   OpaqueValueExpr [[TmpOpV]] {{.*}} 'int' lvalue
142
143
144
145// CHECK-LABEL: FunctionDecl {{.*}} used buzz 'int (int, int)' implicit_instantiation
146// CHECK: CallExpr {{.*}} 'void'
147// CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(inout int)' <FunctionToPointerDecay>
148// CHECK-NEXT:   DeclRefExpr {{.*}} 'void (inout int)' lvalue Function {{.*}} 'fn' 'void (inout int)'
149// CHECK-NEXT: HLSLOutArgExpr {{.*}} 'int' lvalue inout
150// CHECK-NEXT: OpaqueValueExpr [[LVOpV:0x[0-9a-fA-F]+]] {{.*}} 'int' lvalue
151// CHECK-NEXT:   DeclRefExpr  {{.*}} 'int' lvalue ParmVar {{.*}} 'X' 'int'
152// CHECK-NEXT: OpaqueValueExpr [[TmpOpV:0x[0-9a-fA-F]+]] {{.*}} 'int' lvalue
153// CHECK-NEXT:   ImplicitCastExpr  {{.*}} 'int' <LValueToRValue>
154// CHECK-NEXT:     OpaqueValueExpr [[LVOpV]] {{.*}} 'int' lvalue
155// CHECK:      BinaryOperator {{.*}} 'int' lvalue '='
156// CHECK-NEXT:   OpaqueValueExpr [[LVOpV]] {{.*}} 'int' lvalue
157// CHECK:      ImplicitCastExpr  {{.*}} 'int' <LValueToRValue>
158// CHECK-NEXT:   OpaqueValueExpr [[TmpOpV]] {{.*}} 'int' lvalue
159
160
161// CHECK-LABEL: FunctionDecl {{.*}} used buzz 'float (int, float)' implicit_instantiation
162// CHECK: CallExpr {{.*}} 'void'
163// CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(inout int)' <FunctionToPointerDecay>
164// CHECK-NEXT:   DeclRefExpr {{.*}} 'void (inout int)' lvalue Function {{.*}} 'fn' 'void (inout int)'
165// CHECK-NEXT: HLSLOutArgExpr {{.*}} 'int' lvalue inout
166// CHECK-NEXT: OpaqueValueExpr [[LVOpV:0x[0-9a-fA-F]+]] {{.*}} 'int' lvalue
167// CHECK-NEXT:   DeclRefExpr  {{.*}} 'int' lvalue ParmVar {{.*}} 'X' 'int'
168// CHECK-NEXT: OpaqueValueExpr [[TmpOpV:0x[0-9a-fA-F]+]] {{.*}} 'int' lvalue
169// CHECK-NEXT:   ImplicitCastExpr  {{.*}} 'int' <LValueToRValue>
170// CHECK-NEXT:     OpaqueValueExpr [[LVOpV]] {{.*}} 'int' lvalue
171// CHECK:      BinaryOperator {{.*}} 'int' lvalue '='
172// CHECK-NEXT:   OpaqueValueExpr [[LVOpV]] {{.*}} 'int' lvalue
173// CHECK:      ImplicitCastExpr  {{.*}} 'int' <LValueToRValue>
174// CHECK-NEXT:   OpaqueValueExpr [[TmpOpV]] {{.*}} 'int' lvalue
175
176
177// CHECK-LABEL: FunctionDecl {{.*}} used buzz 'double (int, double)' implicit_instantiation
178// CHECK: CallExpr {{.*}} 'void'
179// CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(inout int)' <FunctionToPointerDecay>
180// CHECK-NEXT:   DeclRefExpr {{.*}} 'void (inout int)' lvalue Function {{.*}} 'fn' 'void (inout int)'
181// CHECK-NEXT: HLSLOutArgExpr {{.*}} 'int' lvalue inout
182// CHECK-NEXT: OpaqueValueExpr [[LVOpV:0x[0-9a-fA-F]+]] {{.*}} 'int' lvalue
183// CHECK-NEXT:   DeclRefExpr  {{.*}} 'int' lvalue ParmVar {{.*}} 'X' 'int'
184// CHECK-NEXT: OpaqueValueExpr [[TmpOpV:0x[0-9a-fA-F]+]] {{.*}} 'int' lvalue
185// CHECK-NEXT:   ImplicitCastExpr  {{.*}} 'int' <LValueToRValue>
186// CHECK-NEXT:     OpaqueValueExpr [[LVOpV]] {{.*}} 'int' lvalue
187// CHECK:      BinaryOperator {{.*}} 'int' lvalue '='
188// CHECK-NEXT:   OpaqueValueExpr [[LVOpV]] {{.*}} 'int' lvalue
189// CHECK:      ImplicitCastExpr  {{.*}} 'int' <LValueToRValue>
190// CHECK-NEXT:   OpaqueValueExpr [[TmpOpV]] {{.*}} 'int' lvalue
191
192template <typename T>
193T buzz(int X, T Y) {
194  fn(X);
195  return X + Y;
196}
197
198export void caller() {
199  int X = 2;
200  float Y = 3.3;
201  double Z = 2.2;
202
203  X = wrapper(X);
204  Y = wrapper(Y);
205  Z = wrapper(Z);
206
207  fizz(X);
208  fizz(Y);
209  fizz(Z);
210
211  X = buzz(X, X);
212  Y = buzz(X, Y);
213  Z = buzz(X, Z);
214}
215