Revert "[llvm] Improve llvm.objectsize computation by computing GEP, alloca and mallo...
[llvm-project.git] / clang / test / CodeGenHLSL / BasicFeatures / OutputArguments.hlsl
blob6afead4f233660692b5bcd52233792505d7980ff
1 // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -disable-llvm-passes -emit-llvm -finclude-default-header -o - %s | FileCheck %s --check-prefixes=CHECK,ALL
2 // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -O3 -emit-llvm -finclude-default-header -o - %s | FileCheck %s --check-prefixes=OPT,ALL
4 // Case 1: Simple floating integral conversion.
5 // In this test case a float value is passed to an inout parameter taking an
6 // integer. It is converted to an integer on call and converted back after the
7 // function.
9 // CHECK: define void {{.*}}trunc_Param{{.*}}(ptr noalias noundef nonnull align 4 dereferenceable(4) {{%.*}})
10 void trunc_Param(inout int X) {}
12 // ALL-LABEL: define noundef float {{.*}}case1
13 // CHECK: [[F:%.*]] = alloca float
14 // CHECK: [[ArgTmp:%.*]] = alloca i32
15 // CHECK: [[FVal:%.*]] = load float, ptr {{.*}}
16 // CHECK: [[IVal:%.*]] = fptosi float [[FVal]] to i32
17 // CHECK: store i32 [[IVal]], ptr [[ArgTmp]]
18 // CHECK: call void {{.*}}trunc_Param{{.*}}(ptr noalias noundef nonnull align 4 dereferenceable(4) [[ArgTmp]])
19 // CHECK: [[IRet:%.*]] = load i32, ptr [[ArgTmp]]
20 // CHECK: [[FRet:%.*]] = sitofp i32 [[IRet]] to float
21 // CHECK: store float [[FRet]], ptr [[F]]
22 // OPT: [[IVal:%.*]] = fptosi float {{.*}} to i32
23 // OPT: [[FVal:%.*]] = sitofp i32 [[IVal]] to float
24 // OPT: ret float [[FVal]]
25 export float case1(float F) {
26   trunc_Param(F);
27   return F;
30 // Case 2: Uninitialized `out` parameters.
31 // `out` parameters are not pre-initialized by the caller, so they are
32 // uninitialized in the function. If they are not initialized before the
33 // function returns the value is undefined.
35 // CHECK: define void {{.*}}undef{{.*}}(ptr noalias noundef nonnull align 4 dereferenceable(4) {{%.*}})
36 void undef(out int Z) { }
38 // ALL-LABEL: define noundef i32 {{.*}}case2
39 // CHECK: [[V:%.*]] = alloca i32
40 // CHECK: [[ArgTmp:%.*]] = alloca i32
41 // CHECK-NOT: store {{.*}}, ptr [[ArgTmp]]
42 // CHECK: call void {{.*}}unde{{.*}}(ptr noalias noundef nonnull align 4 dereferenceable(4) [[ArgTmp]])
43 // CHECK-NOT: store {{.*}}, ptr [[ArgTmp]]
44 // CHECK: [[Res:%.*]] = load i32, ptr [[ArgTmp]]
45 // CHECK: store i32 [[Res]], ptr [[V]], align 4
46 // OPT: ret i32 undef
47 export int case2() {
48   int V;
49   undef(V);
50   return V;
53 // Case 3: Simple initialized `out` parameter.
54 // This test should verify that an out parameter value is written to as
55 // expected.
57 // CHECK: define void {{.*}}zero{{.*}}(ptr noalias noundef nonnull align 4 dereferenceable(4) {{%.*}})
58 void zero(out int Z) { Z = 0; }
60 // ALL-LABEL: define noundef i32 {{.*}}case3
61 // CHECK: [[V:%.*]] = alloca i32
62 // CHECK: [[ArgTmp:%.*]] = alloca i32
63 // CHECK-NOT: store {{.*}}, ptr [[ArgTmp]]
64 // CHECK: call void {{.*}}zero{{.*}}(ptr noalias noundef nonnull align 4 dereferenceable(4) [[ArgTmp]])
65 // CHECK-NOT: store {{.*}}, ptr [[ArgTmp]]
66 // CHECK: [[Res:%.*]] = load i32, ptr [[ArgTmp]]
67 // CHECK: store i32 [[Res]], ptr [[V]], align 4
68 // OPT: ret i32 0
69 export int case3() {
70   int V;
71   zero(V);
72   return V;
75 // Case 4: Vector swizzle arguments.
76 // Vector swizzles in HLSL produce lvalues, so they can be used as arguments to
77 // inout parameters and the swizzle is reversed on writeback.
79 // CHECK: define void {{.*}}funky{{.*}}(ptr noalias noundef nonnull align 16 dereferenceable(16) {{%.*}})
80 void funky(inout int3 X) {
81   X.x += 1;
82   X.y += 2;
83   X.z += 3;
86 // ALL-LABEL: define noundef {{.*}}<3 x i32> {{.*}}case4
88 // This block initializes V = 0.xxx.
89 // CHECK:  [[V:%.*]] = alloca <3 x i32>
90 // CHECK:  [[ArgTmp:%.*]] = alloca <3 x i32>
91 // CHECK:  store <1 x i32> zeroinitializer, ptr [[ZeroPtr:%.*]]
92 // CHECK:  [[ZeroV1:%.*]] = load <1 x i32>, ptr [[ZeroPtr]]
93 // CHECK:  [[ZeroV3:%.*]] = shufflevector <1 x i32> [[ZeroV1]], <1 x i32> poison, <3 x i32> zeroinitializer
94 // CHECK:  store <3 x i32> [[ZeroV3]], ptr [[V]]
96 // Shuffle the vector to the temporary.
97 // CHECK:  [[VVal:%.*]] = load <3 x i32>, ptr [[V]]
98 // CHECK:  [[Vyzx:%.*]] = shufflevector <3 x i32> [[VVal]], <3 x i32> poison, <3 x i32> <i32 1, i32 2, i32 0>
99 // CHECK:  store <3 x i32> [[Vyzx]], ptr [[ArgTmp]]
101 // Call the function with the temporary.
102 // CHECK: call void {{.*}}funky{{.*}}(ptr noalias noundef nonnull align 16 dereferenceable(16) [[ArgTmp]])
104 // Shuffle it back.
105 // CHECK:  [[RetVal:%.*]] = load <3 x i32>, ptr [[ArgTmp]]
106 // CHECK:  [[Vxyz:%.*]] = shufflevector <3 x i32> [[RetVal]], <3 x i32> poison, <3 x i32> <i32 2, i32 0, i32 1>
107 // CHECK:  store <3 x i32> [[Vxyz]], ptr [[V]]
109 // OPT: ret <3 x i32> <i32 3, i32 1, i32 2>
110 export int3 case4() {
111   int3 V = 0.xxx;
112   funky(V.yzx);
113   return V;
117 // Case 5: Straightforward inout of a scalar value.
119 // CHECK: define void {{.*}}increment{{.*}}(ptr noalias noundef nonnull align 4 dereferenceable(4) {{%.*}})
120 void increment(inout int I) {
121   I += 1;
124 // ALL-LABEL: define noundef i32 {{.*}}case5
126 // CHECK: [[I:%.*]] = alloca i32
127 // CHECK: [[ArgTmp:%.*]] = alloca i32
128 // CHECK: store i32 4, ptr [[I]]
129 // CHECK: [[IInit:%.*]] = load i32, ptr [[I]]
130 // CHECK: store i32 [[IInit:%.*]], ptr [[ArgTmp]], align 4
131 // CHECK: call void {{.*}}increment{{.*}}(ptr noalias noundef nonnull align 4 dereferenceable(4) [[ArgTmp]])
132 // CHECK: [[RetVal:%.*]] = load i32, ptr [[ArgTmp]]
133 // CHECK: store i32 [[RetVal]], ptr [[I]], align 4
134 // OPT: ret i32 5
135 export int case5() {
136   int I = 4;
137   increment(I);
138   return I;
141 // Case 6: Aggregate out parameters.
142 struct S {
143   int X;
144   float Y;
147 // CHECK: define void {{.*}}init{{.*}}(ptr noalias noundef nonnull align 4 dereferenceable(8) {{%.*}})
148 void init(out S s) {
149   s.X = 3;
150   s.Y = 4;
153 // ALL-LABEL: define noundef i32 {{.*}}case6
155 // CHECK: [[S:%.*]] = alloca %struct.S
156 // CHECK: [[Tmp:%.*]] = alloca %struct.S
157 // CHECK: call void {{.*}}init{{.*}}(ptr noalias noundef nonnull align 4 dereferenceable(8) [[Tmp]])
158 // CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[S]], ptr align 4 [[Tmp]], i32 8, i1 false)
160 // OPT: ret i32 7
161 export int case6() {
162   S s;
163   init(s);
164   return s.X + s.Y;
167 // Case 7: Aggregate inout parameters.
168 struct R {
169   int X;
170   float Y;
173 // CHECK: define void {{.*}}init{{.*}}(ptr noalias noundef nonnull align 4 dereferenceable(8) {{%.*}})
174 void init(inout R s) {
175   s.X = 3;
176   s.Y = 4;
179 // ALL-LABEL: define noundef i32 {{.*}}case7
181 // CHECK: [[S:%.*]] = alloca %struct.R
182 // CHECK: [[Tmp:%.*]] = alloca %struct.R
183 // CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Tmp]], ptr align 4 [[S]], i32 8, i1 false)
184 // CHECK: call void {{.*}}init{{.*}}(ptr noalias noundef nonnull align 4 dereferenceable(8) [[Tmp]])
185 // CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[S]], ptr align 4 [[Tmp]], i32 8, i1 false)
187 // OPT: ret i32 7
188 export int case7() {
189   R s;
190   init(s);
191   return s.X + s.Y;
195 // Case 8: Non-scalars with a cast expression.
197 // CHECK: define void {{.*}}trunc_vec{{.*}}(ptr noalias noundef nonnull align 16 dereferenceable(16) {{%.*}})
198 void trunc_vec(inout int3 V) {}
200 // ALL-LABEL: define noundef <3 x float> {{.*}}case8
202 // CHECK: [[V:%.*]] = alloca <3 x float>
203 // CHECK: [[Tmp:%.*]] = alloca <3 x i32>
204 // CHECK: [[FVal:%.*]] = load <3 x float>, ptr [[V]]
205 // CHECK: [[IVal:%.*]] = fptosi <3 x float> [[FVal]] to <3 x i32>
206 // CHECK: store <3 x i32> [[IVal]], ptr [[Tmp]]
207 // CHECK: call void {{.*}}trunc_vec{{.*}}(ptr noalias noundef nonnull align 16 dereferenceable(16) [[Tmp]])
208 // CHECK: [[IRet:%.*]] = load <3 x i32>, ptr [[Tmp]]
209 // CHECK: [[FRet:%.*]] = sitofp <3 x i32> [[IRet]] to <3 x float>
210 // CHECK: store <3 x float> [[FRet]], ptr [[V]]
212 // OPT: [[IVal:%.*]] = fptosi <3 x float> {{.*}} to <3 x i32>
213 // OPT: [[FVal:%.*]] = sitofp <3 x i32> [[IVal]] to <3 x float>
214 // OPT: ret <3 x float> [[FVal]]
216 export float3 case8(float3 V) {
217   trunc_vec(V);
218   return V;
221 // Case 9: Side-effecting lvalue argument expression!
223 void do_nothing(inout int V) {}
225 // ALL-LABEL: define noundef i32 {{.*}}case9
226 // CHECK: [[V:%.*]] = alloca i32
227 // CHECK: [[Tmp:%.*]] = alloca i32
228 // CHECK: store i32 0, ptr [[V]]
229 // CHECK: [[VVal:%.*]] = load i32, ptr [[V]]
230 // CHECK: [[VInc:%.*]] = add nsw i32 [[VVal]], 1
231 // CHECK: store i32 [[VInc]], ptr [[V]]
232 // CHECK: [[VArg:%.*]] = load i32, ptr [[V]]
233 // CHECK-NOT: add
234 // CHECK: store i32 [[VArg]], ptr [[Tmp]]
235 // CHECK: call void {{.*}}do_nothing{{.*}}(ptr noalias noundef nonnull align 4 dereferenceable(4) [[Tmp]])
236 // CHECK: [[RetVal:%.*]] = load i32, ptr [[Tmp]]
237 // CHECK: store i32 [[RetVal]], ptr [[V]]
239 // OPT: ret i32 1
240 export int case9() {
241   int V = 0;
242   do_nothing(++V);
243   return V;
246 // Case 10: Verify argument writeback ordering for aliasing arguments.
248 void order_matters(inout int X, inout int Y) {
249   Y = 2;
250   X = 1;
253 // ALL-LABEL: define noundef i32 {{.*}}case10
255 // CHECK: [[V:%.*]] = alloca i32
256 // CHECK: [[Tmp0:%.*]] = alloca i32
257 // CHECK: [[Tmp1:%.*]] = alloca i32
258 // CHECK: store i32 0, ptr [[V]]
259 // CHECK: [[VVal:%.*]] = load i32, ptr [[V]]
260 // CHECK: store i32 [[VVal]], ptr [[Tmp0]]
261 // CHECK: [[VVal:%.*]] = load i32, ptr [[V]]
262 // CHECK: store i32 [[VVal]], ptr [[Tmp1]]
263 // CHECK: call void {{.*}}order_matters{{.*}}(ptr noalias noundef nonnull align 4 dereferenceable(4) [[Tmp0]], ptr noalias noundef nonnull align 4 dereferenceable(4) [[Tmp1]])
264 // CHECK: [[Arg1Val:%.*]] = load i32, ptr [[Tmp0]]
265 // CHECK: store i32 [[Arg1Val]], ptr [[V]]
266 // CHECK: [[Arg2Val:%.*]] = load i32, ptr [[Tmp1]]
267 // CHECK: store i32 [[Arg2Val]], ptr [[V]]
269 // OPT: ret i32 2
270 export int case10() {
271   int V = 0;
272   order_matters(V, V);
273   return V;
276 // Case 11: Verify inout on bitfield lvalues
278 struct B {
279   int X : 8;
280   int Y : 8;
283 void setFour(inout int I) {
284   I = 4;
287 // ALL-LABEL: define {{.*}} i32 {{.*}}case11
289 // CHECK: [[B:%.*]] = alloca %struct.B
290 // CHECK: [[Tmp:%.*]] = alloca i32
292 // CHECK: [[BFLoad:%.*]] = load i16, ptr [[B]]
293 // CHECK: [[BFshl:%.*]] = shl i16 [[BFLoad]], 8
294 // CHECK: [[BFashr:%.*]] = ashr i16 [[BFshl]], 8
295 // CHECK: [[BFcast:%.*]] = sext i16 [[BFashr]] to i32
296 // CHECK: store i32 [[BFcast]], ptr [[Tmp]]
297 // CHECK: call void {{.*}}setFour{{.*}}(ptr noalias noundef nonnull align 4 dereferenceable(4) [[Tmp]])
298 // CHECK: [[RetVal:%.*]] = load i32, ptr [[Tmp]]
299 // CHECK: [[TruncVal:%.*]] = trunc i32 [[RetVal]] to i16
300 // CHECK: [[BFLoad:%.*]] = load i16, ptr [[B]]
301 // CHECK: [[BFValue:%.*]] = and i16 [[TruncVal]], 255
302 // CHECK: [[ZerodField:%.*]] = and i16 [[BFLoad]], -256
303 // CHECK: [[BFSet:%.*]] = or i16 [[ZerodField]], [[BFValue]]
304 // CHECK: store i16 [[BFSet]], ptr [[B]]
306 // OPT: ret i32 8
307 export int case11() {
308   B b = {1 , 2};
309   setFour(b.X);
310   return b.X * b.Y;
313 // Case 12: Uninitialized out parameters are undefined
315 void oops(out int X) {}
316 // ALL-LABEL: define {{.*}} i32 {{.*}}case12
318 // CHECK: [[V:%.*]] = alloca i32
319 // CHECK: [[Tmp:%.*]] = alloca i32
320 // CHECK-NOT: store {{.*}}, ptr [[Tmp]]
321 // CHECK: call void {{.*}}oops{{.*}}(ptr noalias noundef nonnull align 4 dereferenceable(4) [[Tmp]])
322 // CHECK: [[ArgVal:%.*]] = load i32, ptr [[Tmp]]
323 // CHECK: store i32 [[ArgVal]], ptr [[V]]
325 // OPT:  ret i32 undef
326 export int case12() {
327   int V = 0;
328   oops(V);
329   return V;