1// Copyright (c) 2017 Google Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include <string>
16
17#include "source/opt/scalar_replacement_pass.h"
18#include "test/opt/assembly_builder.h"
19#include "test/opt/pass_fixture.h"
20#include "test/opt/pass_utils.h"
21
22namespace spvtools {
23namespace opt {
24namespace {
25
26using ScalarReplacementPassName = ::testing::Test;
27
28TEST_F(ScalarReplacementPassName, Default) {
29  auto srp = ScalarReplacementPass();
30  EXPECT_STREQ(srp.name(), "scalar-replacement=100");
31}
32
33TEST_F(ScalarReplacementPassName, Large) {
34  auto srp = ScalarReplacementPass(0xffffffffu);
35  EXPECT_STREQ(srp.name(), "scalar-replacement=4294967295");
36}
37
38using ScalarReplacementTest = PassTest<::testing::Test>;
39
40TEST_F(ScalarReplacementTest, SimpleStruct) {
41  const std::string text = R"(
42;
43; CHECK: [[struct:%\w+]] = OpTypeStruct [[elem:%\w+]]
44; CHECK: [[struct_ptr:%\w+]] = OpTypePointer Function [[struct]]
45; CHECK: [[elem_ptr:%\w+]] = OpTypePointer Function [[elem]]
46; CHECK: OpConstantNull [[struct]]
47; CHECK: [[null:%\w+]] = OpConstantNull [[elem]]
48; CHECK-NOT: OpVariable [[struct_ptr]]
49; CHECK: [[one:%\w+]] = OpVariable [[elem_ptr]] Function [[null]]
50; CHECK-NEXT: [[two:%\w+]] = OpVariable [[elem_ptr]] Function [[null]]
51; CHECK-NOT: OpVariable [[elem_ptr]] Function [[null]]
52; CHECK-NOT: OpVariable [[struct_ptr]]
53; CHECK-NOT: OpInBoundsAccessChain
54; CHECK: [[l1:%\w+]] = OpLoad [[elem]] [[two]]
55; CHECK-NOT: OpAccessChain
56; CHECK: [[l2:%\w+]] = OpLoad [[elem]] [[one]]
57; CHECK: OpIAdd [[elem]] [[l1]] [[l2]]
58;
59OpCapability Shader
60OpCapability Linkage
61OpMemoryModel Logical GLSL450
62OpName %6 "simple_struct"
63%1 = OpTypeVoid
64%2 = OpTypeInt 32 0
65%3 = OpTypeStruct %2 %2 %2 %2
66%4 = OpTypePointer Function %3
67%5 = OpTypePointer Function %2
68%6 = OpTypeFunction %2
69%7 = OpConstantNull %3
70%8 = OpConstant %2 0
71%9 = OpConstant %2 1
72%10 = OpConstant %2 2
73%11 = OpConstant %2 3
74%12 = OpFunction %2 None %6
75%13 = OpLabel
76%14 = OpVariable %4 Function %7
77%15 = OpInBoundsAccessChain %5 %14 %8
78%16 = OpLoad %2 %15
79%17 = OpAccessChain %5 %14 %10
80%18 = OpLoad %2 %17
81%19 = OpIAdd %2 %16 %18
82OpReturnValue %19
83OpFunctionEnd
84  )";
85
86  SinglePassRunAndMatch<ScalarReplacementPass>(text, true);
87}
88
89TEST_F(ScalarReplacementTest, StructInitialization) {
90  const std::string text = R"(
91;
92; CHECK: [[elem:%\w+]] = OpTypeInt 32 0
93; CHECK: [[struct:%\w+]] = OpTypeStruct [[elem]] [[elem]] [[elem]] [[elem]]
94; CHECK: [[struct_ptr:%\w+]] = OpTypePointer Function [[struct]]
95; CHECK: [[elem_ptr:%\w+]] = OpTypePointer Function [[elem]]
96; CHECK: [[zero:%\w+]] = OpConstant [[elem]] 0
97; CHECK: [[undef:%\w+]] = OpUndef [[elem]]
98; CHECK: [[two:%\w+]] = OpConstant [[elem]] 2
99; CHECK: [[null:%\w+]] = OpConstantNull [[elem]]
100; CHECK-NOT: OpVariable [[struct_ptr]]
101; CHECK: OpVariable [[elem_ptr]] Function [[null]]
102; CHECK-NEXT: OpVariable [[elem_ptr]] Function [[two]]
103; CHECK-NOT: OpVariable [[elem_ptr]] Function [[undef]]
104; CHECK-NEXT: OpVariable [[elem_ptr]] Function
105; CHECK-NEXT: OpVariable [[elem_ptr]] Function [[zero]]
106; CHECK-NOT: OpVariable [[elem_ptr]] Function [[undef]]
107;
108OpCapability Shader
109OpCapability Linkage
110OpMemoryModel Logical GLSL450
111OpName %6 "struct_init"
112%1 = OpTypeVoid
113%2 = OpTypeInt 32 0
114%3 = OpTypeStruct %2 %2 %2 %2
115%4 = OpTypePointer Function %3
116%20 = OpTypePointer Function %2
117%6 = OpTypeFunction %1
118%7 = OpConstant %2 0
119%8 = OpUndef %2
120%9 = OpConstant %2 2
121%30 = OpConstant %2 1
122%31 = OpConstant %2 3
123%10 = OpConstantNull %2
124%11 = OpConstantComposite %3 %7 %8 %9 %10
125%12 = OpFunction %1 None %6
126%13 = OpLabel
127%14 = OpVariable %4 Function %11
128%15 = OpAccessChain %20 %14 %7
129OpStore %15 %10
130%16 = OpAccessChain %20 %14 %9
131OpStore %16 %10
132%17 = OpAccessChain %20 %14 %30
133OpStore %17 %10
134%18 = OpAccessChain %20 %14 %31
135OpStore %18 %10
136OpReturn
137OpFunctionEnd
138  )";
139
140  SinglePassRunAndMatch<ScalarReplacementPass>(text, true);
141}
142
143TEST_F(ScalarReplacementTest, SpecConstantInitialization) {
144  const std::string text = R"(
145;
146; CHECK: [[int:%\w+]] = OpTypeInt 32 0
147; CHECK: [[struct:%\w+]] = OpTypeStruct [[int]] [[int]]
148; CHECK: [[struct_ptr:%\w+]] = OpTypePointer Function [[struct]]
149; CHECK: [[int_ptr:%\w+]] = OpTypePointer Function [[int]]
150; CHECK: [[spec_comp:%\w+]] = OpSpecConstantComposite [[struct]]
151; CHECK: [[ex0:%\w+]] = OpSpecConstantOp [[int]] CompositeExtract [[spec_comp]] 0
152; CHECK: [[ex1:%\w+]] = OpSpecConstantOp [[int]] CompositeExtract [[spec_comp]] 1
153; CHECK-NOT: OpVariable [[struct]]
154; CHECK: OpVariable [[int_ptr]] Function [[ex1]]
155; CHECK-NEXT: OpVariable [[int_ptr]] Function [[ex0]]
156; CHECK-NOT: OpVariable [[struct]]
157;
158OpCapability Shader
159OpCapability Linkage
160OpMemoryModel Logical GLSL450
161OpName %6 "spec_const"
162%1 = OpTypeVoid
163%2 = OpTypeInt 32 0
164%3 = OpTypeStruct %2 %2
165%4 = OpTypePointer Function %3
166%20 = OpTypePointer Function %2
167%5 = OpTypeFunction %1
168%6 = OpConstant %2 0
169%30 = OpConstant %2 1
170%7 = OpSpecConstant %2 0
171%8 = OpSpecConstantOp %2 IAdd %7 %7
172%9 = OpSpecConstantComposite %3 %7 %8
173%10 = OpFunction %1 None %5
174%11 = OpLabel
175%12 = OpVariable %4 Function %9
176%13 = OpAccessChain %20 %12 %6
177%14 = OpLoad %2 %13
178%15 = OpAccessChain %20 %12 %30
179%16 = OpLoad %2 %15
180OpReturn
181OpFunctionEnd
182  )";
183
184  SinglePassRunAndMatch<ScalarReplacementPass>(text, true);
185}
186
187// TODO(alanbaker): Re-enable when vector and matrix scalarization is supported.
188// TEST_F(ScalarReplacementTest, VectorInitialization) {
189//  const std::string text = R"(
190// ;
191// ; CHECK: [[elem:%\w+]] = OpTypeInt 32 0
192// ; CHECK: [[vector:%\w+]] = OpTypeVector [[elem]] 4
193// ; CHECK: [[vector_ptr:%\w+]] = OpTypePointer Function [[vector]]
194// ; CHECK: [[elem_ptr:%\w+]] = OpTypePointer Function [[elem]]
195// ; CHECK: [[zero:%\w+]] = OpConstant [[elem]] 0
196// ; CHECK: [[undef:%\w+]] = OpUndef [[elem]]
197// ; CHECK: [[two:%\w+]] = OpConstant [[elem]] 2
198// ; CHECK: [[null:%\w+]] = OpConstantNull [[elem]]
199// ; CHECK-NOT: OpVariable [[vector_ptr]]
200// ; CHECK: OpVariable [[elem_ptr]] Function [[zero]]
201// ; CHECK-NOT: OpVariable [[elem_ptr]] Function [[undef]]
202// ; CHECK-NEXT: OpVariable [[elem_ptr]] Function
203// ; CHECK-NEXT: OpVariable [[elem_ptr]] Function [[two]]
204// ; CHECK-NEXT: OpVariable [[elem_ptr]] Function [[null]]
205// ; CHECK-NOT: OpVariable [[elem_ptr]] Function [[undef]]
206// ;
207//  OpCapability Shader
208//  OpCapability Linkage
209//  OpMemoryModel Logical GLSL450
210//  OpName %6 "vector_init"
211// %1 = OpTypeVoid
212// %2 = OpTypeInt 32 0
213// %3 = OpTypeVector %2 4
214// %4 = OpTypePointer Function %3
215// %20 = OpTypePointer Function %2
216// %6 = OpTypeFunction %1
217// %7 = OpConstant %2 0
218// %8 = OpUndef %2
219// %9 = OpConstant %2 2
220// %30 = OpConstant %2 1
221// %31 = OpConstant %2 3
222// %10 = OpConstantNull %2
223// %11 = OpConstantComposite %3 %10 %9 %8 %7
224// %12 = OpFunction %1 None %6
225// %13 = OpLabel
226// %14 = OpVariable %4 Function %11
227// %15 = OpAccessChain %20 %14 %7
228//  OpStore %15 %10
229// %16 = OpAccessChain %20 %14 %9
230//  OpStore %16 %10
231// %17 = OpAccessChain %20 %14 %30
232//  OpStore %17 %10
233// %18 = OpAccessChain %20 %14 %31
234//  OpStore %18 %10
235//  OpReturn
236//  OpFunctionEnd
237//   )";
238//
239//   SinglePassRunAndMatch<opt::ScalarReplacementPass>(text, true);
240// }
241//
242//  TEST_F(ScalarReplacementTest, MatrixInitialization) {
243//   const std::string text = R"(
244// ;
245// ; CHECK: [[float:%\w+]] = OpTypeFloat 32
246// ; CHECK: [[vector:%\w+]] = OpTypeVector [[float]] 2
247// ; CHECK: [[matrix:%\w+]] = OpTypeMatrix [[vector]] 2
248// ; CHECK: [[matrix_ptr:%\w+]] = OpTypePointer Function [[matrix]]
249// ; CHECK: [[float_ptr:%\w+]] = OpTypePointer Function [[float]]
250// ; CHECK: [[vec_ptr:%\w+]] = OpTypePointer Function [[vector]]
251// ; CHECK: [[zerof:%\w+]] = OpConstant [[float]] 0
252// ; CHECK: [[onef:%\w+]] = OpConstant [[float]] 1
253// ; CHECK: [[one_zero:%\w+]] = OpConstantComposite [[vector]] [[onef]]
254// [[zerof]] ; CHECK: [[zero_one:%\w+]] = OpConstantComposite [[vector]]
255// [[zerof]] [[onef]] ; CHECK: [[const_mat:%\w+]] = OpConstantComposite
256// [[matrix]] [[one_zero]]
257// [[zero_one]] ; CHECK-NOT: OpVariable [[matrix]] ; CHECK-NOT: OpVariable
258// [[vector]] Function [[one_zero]] ; CHECK: [[f1:%\w+]] = OpVariable
259// [[float_ptr]] Function [[zerof]] ; CHECK-NEXT: [[f2:%\w+]] = OpVariable
260// [[float_ptr]] Function [[onef]] ; CHECK-NEXT: [[vec_var:%\w+]] = OpVariable
261// [[vec_ptr]] Function [[zero_one]] ; CHECK-NOT: OpVariable [[matrix]] ;
262//  CHECK-NOT: OpVariable [[vector]] Function [[one_zero]]
263// ;
264//  OpCapability Shader
265//  OpCapability Linkage
266//  OpMemoryModel Logical GLSL450
267//  OpName %7 "matrix_init"
268// %1 = OpTypeVoid
269// %2 = OpTypeFloat 32
270// %3 = OpTypeVector %2 2
271// %4 = OpTypeMatrix %3 2
272// %5 = OpTypePointer Function %4
273// %6 = OpTypePointer Function %2
274// %30 = OpTypePointer Function %3
275// %10 = OpTypeInt 32 0
276// %7 = OpTypeFunction %1 %10
277// %8 = OpConstant %2 0.0
278// %9 = OpConstant %2 1.0
279// %11 = OpConstant %10 0
280// %12 = OpConstant %10 1
281// %13 = OpConstantComposite %3 %9 %8
282// %14 = OpConstantComposite %3 %8 %9
283// %15 = OpConstantComposite %4 %13 %14
284// %16 = OpFunction %1 None %7
285// %31 = OpFunctionParameter %10
286// %17 = OpLabel
287// %18 = OpVariable %5 Function %15
288// %19 = OpAccessChain %6 %18 %11 %12
289//  OpStore %19 %8
290// %20 = OpAccessChain %6 %18 %11 %11
291//  OpStore %20 %8
292// %21 = OpAccessChain %30 %18 %12
293//  OpStore %21 %14
294//  OpReturn
295//  OpFunctionEnd
296//   )";
297//
298//   SinglePassRunAndMatch<opt::ScalarReplacementPass>(text, true);
299// }
300
301TEST_F(ScalarReplacementTest, ElideAccessChain) {
302  const std::string text = R"(
303;
304; CHECK: [[var:%\w+]] = OpVariable
305; CHECK-NOT: OpAccessChain
306; CHECK: OpStore [[var]]
307;
308OpCapability Shader
309OpCapability Linkage
310OpMemoryModel Logical GLSL450
311OpName %6 "elide_access_chain"
312%1 = OpTypeVoid
313%2 = OpTypeInt 32 0
314%3 = OpTypeStruct %2 %2 %2 %2
315%4 = OpTypePointer Function %3
316%20 = OpTypePointer Function %2
317%6 = OpTypeFunction %1
318%7 = OpConstant %2 0
319%8 = OpUndef %2
320%9 = OpConstant %2 2
321%10 = OpConstantNull %2
322%11 = OpConstantComposite %3 %7 %8 %9 %10
323%12 = OpFunction %1 None %6
324%13 = OpLabel
325%14 = OpVariable %4 Function %11
326%15 = OpAccessChain %20 %14 %7
327OpStore %15 %10
328OpReturn
329OpFunctionEnd
330  )";
331
332  SinglePassRunAndMatch<ScalarReplacementPass>(text, true);
333}
334
335TEST_F(ScalarReplacementTest, ElideMultipleAccessChains) {
336  const std::string text = R"(
337;
338; CHECK: [[var:%\w+]] = OpVariable
339; CHECK-NOT: OpInBoundsAccessChain
340; CHECK OpStore [[var]]
341;
342OpCapability Shader
343OpCapability Linkage
344OpMemoryModel Logical GLSL450
345OpName %6 "elide_two_access_chains"
346%1 = OpTypeVoid
347%2 = OpTypeFloat 32
348%3 = OpTypeStruct %2 %2
349%4 = OpTypeStruct %3 %3
350%5 = OpTypePointer Function %4
351%6 = OpTypePointer Function %2
352%7 = OpTypeFunction %1
353%8 = OpConstant %2 0.0
354%9 = OpConstant %2 1.0
355%10 = OpTypeInt 32 0
356%11 = OpConstant %10 0
357%12 = OpConstant %10 1
358%13 = OpConstantComposite %3 %9 %8
359%14 = OpConstantComposite %3 %8 %9
360%15 = OpConstantComposite %4 %13 %14
361%16 = OpFunction %1 None %7
362%17 = OpLabel
363%18 = OpVariable %5 Function %15
364%19 = OpInBoundsAccessChain %6 %18 %11 %12
365OpStore %19 %8
366OpReturn
367OpFunctionEnd
368  )";
369
370  SinglePassRunAndMatch<ScalarReplacementPass>(text, true);
371}
372
373TEST_F(ScalarReplacementTest, ReplaceAccessChain) {
374  const std::string text = R"(
375;
376; CHECK: [[param:%\w+]] = OpFunctionParameter
377; CHECK: [[var:%\w+]] = OpVariable
378; CHECK: [[access:%\w+]] = OpAccessChain {{%\w+}} [[var]] [[param]]
379; CHECK: OpStore [[access]]
380;
381OpCapability Shader
382OpCapability Linkage
383OpMemoryModel Logical GLSL450
384OpName %7 "replace_access_chain"
385%1 = OpTypeVoid
386%2 = OpTypeFloat 32
387%10 = OpTypeInt 32 0
388%uint_2 = OpConstant %10 2
389%3 = OpTypeArray %2 %uint_2
390%4 = OpTypeStruct %3 %3
391%5 = OpTypePointer Function %4
392%20 = OpTypePointer Function %3
393%6 = OpTypePointer Function %2
394%7 = OpTypeFunction %1 %10
395%8 = OpConstant %2 0.0
396%9 = OpConstant %2 1.0
397%11 = OpConstant %10 0
398%12 = OpConstant %10 1
399%13 = OpConstantComposite %3 %9 %8
400%14 = OpConstantComposite %3 %8 %9
401%15 = OpConstantComposite %4 %13 %14
402%16 = OpFunction %1 None %7
403%32 = OpFunctionParameter %10
404%17 = OpLabel
405%18 = OpVariable %5 Function %15
406%19 = OpAccessChain %6 %18 %11 %32
407OpStore %19 %8
408OpReturn
409OpFunctionEnd
410  )";
411
412  SinglePassRunAndMatch<ScalarReplacementPass>(text, true);
413}
414
415TEST_F(ScalarReplacementTest, ArrayInitialization) {
416  const std::string text = R"(
417;
418; CHECK: [[float:%\w+]] = OpTypeFloat 32
419; CHECK: [[array:%\w+]] = OpTypeArray
420; CHECK: [[array_ptr:%\w+]] = OpTypePointer Function [[array]]
421; CHECK: [[float_ptr:%\w+]] = OpTypePointer Function [[float]]
422; CHECK: [[float0:%\w+]] = OpConstant [[float]] 0
423; CHECK: [[float1:%\w+]] = OpConstant [[float]] 1
424; CHECK: [[float2:%\w+]] = OpConstant [[float]] 2
425; CHECK-NOT: OpVariable [[array_ptr]]
426; CHECK: [[var0:%\w+]] = OpVariable [[float_ptr]] Function [[float0]]
427; CHECK-NEXT: [[var1:%\w+]] = OpVariable [[float_ptr]] Function [[float1]]
428; CHECK-NEXT: [[var2:%\w+]] = OpVariable [[float_ptr]] Function [[float2]]
429; CHECK-NOT: OpVariable [[array_ptr]]
430;
431OpCapability Shader
432OpCapability Linkage
433OpMemoryModel Logical GLSL450
434OpName %func "array_init"
435%void = OpTypeVoid
436%uint = OpTypeInt 32 0
437%float = OpTypeFloat 32
438%uint_0 = OpConstant %uint 0
439%uint_1 = OpConstant %uint 1
440%uint_2 = OpConstant %uint 2
441%uint_3 = OpConstant %uint 3
442%float_array = OpTypeArray %float %uint_3
443%array_ptr = OpTypePointer Function %float_array
444%float_ptr = OpTypePointer Function %float
445%float_0 = OpConstant %float 0
446%float_1 = OpConstant %float 1
447%float_2 = OpConstant %float 2
448%const_array = OpConstantComposite %float_array %float_2 %float_1 %float_0
449%func = OpTypeFunction %void
450%1 = OpFunction %void None %func
451%2 = OpLabel
452%3 = OpVariable %array_ptr Function %const_array
453%4 = OpInBoundsAccessChain %float_ptr %3 %uint_0
454OpStore %4 %float_0
455%5 = OpInBoundsAccessChain %float_ptr %3 %uint_1
456OpStore %5 %float_0
457%6 = OpInBoundsAccessChain %float_ptr %3 %uint_2
458OpStore %6 %float_0
459OpReturn
460OpFunctionEnd
461  )";
462
463  SinglePassRunAndMatch<ScalarReplacementPass>(text, true);
464}
465
466TEST_F(ScalarReplacementTest, NonUniformCompositeInitialization) {
467  const std::string text = R"(
468;
469; CHECK: [[uint:%\w+]] = OpTypeInt 32 0
470; CHECK: [[long:%\w+]] = OpTypeInt 64 1
471; CHECK: [[dvector:%\w+]] = OpTypeVector
472; CHECK: [[vector:%\w+]] = OpTypeVector
473; CHECK: [[array:%\w+]] = OpTypeArray
474; CHECK: [[matrix:%\w+]] = OpTypeMatrix
475; CHECK: [[struct1:%\w+]] = OpTypeStruct [[uint]] [[vector]]
476; CHECK: [[struct2:%\w+]] = OpTypeStruct [[struct1]] [[matrix]] [[array]] [[uint]]
477; CHECK: [[struct1_ptr:%\w+]] = OpTypePointer Function [[struct1]]
478; CHECK: [[matrix_ptr:%\w+]] = OpTypePointer Function [[matrix]]
479; CHECK: [[array_ptr:%\w+]] = OpTypePointer Function [[array]]
480; CHECK: [[uint_ptr:%\w+]] = OpTypePointer Function [[uint]]
481; CHECK: [[struct2_ptr:%\w+]] = OpTypePointer Function [[struct2]]
482; CHECK: [[const_array:%\w+]] = OpConstantComposite [[array]]
483; CHECK: [[const_matrix:%\w+]] = OpConstantNull [[matrix]]
484; CHECK: [[const_struct1:%\w+]] = OpConstantComposite [[struct1]]
485; CHECK: OpUndef [[uint]]
486; CHECK: OpUndef [[vector]]
487; CHECK: OpUndef [[long]]
488; CHECK: OpFunction
489; CHECK-NOT: OpVariable [[struct2_ptr]] Function
490; CHECK: OpVariable [[uint_ptr]] Function
491; CHECK-NEXT: OpVariable [[matrix_ptr]] Function [[const_matrix]]
492; CHECK-NOT: OpVariable [[struct1_ptr]] Function [[const_struct1]]
493; CHECK-NOT: OpVariable [[struct2_ptr]] Function
494;
495OpCapability Shader
496OpCapability Linkage
497OpCapability Int64
498OpCapability Float64
499OpMemoryModel Logical GLSL450
500OpName %func "non_uniform_composite_init"
501%void = OpTypeVoid
502%uint = OpTypeInt 32 0
503%int64 = OpTypeInt 64 1
504%float = OpTypeFloat 32
505%double = OpTypeFloat 64
506%double2 = OpTypeVector %double 2
507%float4 = OpTypeVector %float 4
508%int64_0 = OpConstant %int64 0
509%int64_1 = OpConstant %int64 1
510%int64_2 = OpConstant %int64 2
511%int64_3 = OpConstant %int64 3
512%int64_array3 = OpTypeArray %int64 %int64_3
513%matrix_double2 = OpTypeMatrix %double2 2
514%struct1 = OpTypeStruct %uint %float4
515%struct2 = OpTypeStruct %struct1 %matrix_double2 %int64_array3 %uint
516%struct1_ptr = OpTypePointer Function %struct1
517%matrix_double2_ptr = OpTypePointer Function %matrix_double2
518%int64_array_ptr = OpTypePointer Function %int64_array3
519%uint_ptr = OpTypePointer Function %uint
520%struct2_ptr = OpTypePointer Function %struct2
521%const_uint = OpConstant %uint 0
522%const_int64_array = OpConstantComposite %int64_array3 %int64_0 %int64_1 %int64_2
523%const_double2 = OpConstantNull %double2
524%const_matrix_double2 = OpConstantNull %matrix_double2
525%undef_float4 = OpUndef %float4
526%const_struct1 = OpConstantComposite %struct1 %const_uint %undef_float4
527%const_struct2 = OpConstantComposite %struct2 %const_struct1 %const_matrix_double2 %const_int64_array %const_uint
528%func = OpTypeFunction %void
529%1 = OpFunction %void None %func
530%2 = OpLabel
531%var = OpVariable %struct2_ptr Function %const_struct2
532%3 = OpAccessChain %struct1_ptr %var %int64_0
533OpStore %3 %const_struct1
534%4 = OpAccessChain %matrix_double2_ptr %var %int64_1
535OpStore %4 %const_matrix_double2
536%5 = OpAccessChain %int64_array_ptr %var %int64_2
537OpStore %5 %const_int64_array
538%6 = OpAccessChain %uint_ptr %var %int64_3
539OpStore %6 %const_uint
540OpReturn
541OpFunctionEnd
542  )";
543
544  SinglePassRunAndMatch<ScalarReplacementPass>(text, true);
545}
546
547TEST_F(ScalarReplacementTest, ElideUncombinedAccessChains) {
548  const std::string text = R"(
549;
550; CHECK: [[uint:%\w+]] = OpTypeInt 32 0
551; CHECK: [[uint_ptr:%\w+]] = OpTypePointer Function [[uint]]
552; CHECK: [[const:%\w+]] = OpConstant [[uint]] 0
553; CHECK: [[var:%\w+]] = OpVariable [[uint_ptr]] Function
554; CHECK-NOT: OpAccessChain
555; CHECK: OpStore [[var]] [[const]]
556;
557OpCapability Shader
558OpCapability Linkage
559OpMemoryModel Logical GLSL450
560OpName %func "elide_uncombined_access_chains"
561%void = OpTypeVoid
562%uint = OpTypeInt 32 0
563%struct1 = OpTypeStruct %uint
564%struct2 = OpTypeStruct %struct1
565%uint_ptr = OpTypePointer Function %uint
566%struct1_ptr = OpTypePointer Function %struct1
567%struct2_ptr = OpTypePointer Function %struct2
568%uint_0 = OpConstant %uint 0
569%func = OpTypeFunction %void
570%1 = OpFunction %void None %func
571%2 = OpLabel
572%var = OpVariable %struct2_ptr Function
573%3 = OpAccessChain %struct1_ptr %var %uint_0
574%4 = OpAccessChain %uint_ptr %3 %uint_0
575OpStore %4 %uint_0
576OpReturn
577OpFunctionEnd
578  )";
579
580  SinglePassRunAndMatch<ScalarReplacementPass>(text, true);
581}
582
583TEST_F(ScalarReplacementTest, ElideSingleUncombinedAccessChains) {
584  const std::string text = R"(
585;
586; CHECK: [[uint:%\w+]] = OpTypeInt 32 0
587; CHECK: [[array:%\w+]] = OpTypeArray [[uint]]
588; CHECK: [[array_ptr:%\w+]] = OpTypePointer Function [[array]]
589; CHECK: [[const:%\w+]] = OpConstant [[uint]] 0
590; CHECK: [[param:%\w+]] = OpFunctionParameter [[uint]]
591; CHECK: [[var:%\w+]] = OpVariable [[array_ptr]] Function
592; CHECK: [[access:%\w+]] = OpAccessChain {{.*}} [[var]] [[param]]
593; CHECK: OpStore [[access]] [[const]]
594;
595OpCapability Shader
596OpCapability Linkage
597OpMemoryModel Logical GLSL450
598OpName %func "elide_single_uncombined_access_chains"
599%void = OpTypeVoid
600%uint = OpTypeInt 32 0
601%uint_1 = OpConstant %uint 1
602%array = OpTypeArray %uint %uint_1
603%struct2 = OpTypeStruct %array
604%uint_ptr = OpTypePointer Function %uint
605%array_ptr = OpTypePointer Function %array
606%struct2_ptr = OpTypePointer Function %struct2
607%uint_0 = OpConstant %uint 0
608%func = OpTypeFunction %void %uint
609%1 = OpFunction %void None %func
610%param = OpFunctionParameter %uint
611%2 = OpLabel
612%var = OpVariable %struct2_ptr Function
613%3 = OpAccessChain %array_ptr %var %uint_0
614%4 = OpAccessChain %uint_ptr %3 %param
615OpStore %4 %uint_0
616OpReturn
617OpFunctionEnd
618  )";
619
620  SinglePassRunAndMatch<ScalarReplacementPass>(text, true);
621}
622
623TEST_F(ScalarReplacementTest, ReplaceWholeLoad) {
624  const std::string text = R"(
625;
626; CHECK: [[uint:%\w+]] = OpTypeInt 32 0
627; CHECK: [[struct1:%\w+]] = OpTypeStruct [[uint]] [[uint]]
628; CHECK: [[uint_ptr:%\w+]] = OpTypePointer Function [[uint]]
629; CHECK: [[const:%\w+]] = OpConstant [[uint]] 0
630; CHECK: [[var1:%\w+]] = OpVariable [[uint_ptr]] Function
631; CHECK: [[var0:%\w+]] = OpVariable [[uint_ptr]] Function
632; CHECK: [[l1:%\w+]] = OpLoad [[uint]] [[var1]]
633; CHECK: [[l0:%\w+]] = OpLoad [[uint]] [[var0]]
634; CHECK: OpCompositeConstruct [[struct1]] [[l0]] [[l1]]
635;
636OpCapability Shader
637OpCapability Linkage
638OpMemoryModel Logical GLSL450
639OpName %func "replace_whole_load"
640%void = OpTypeVoid
641%uint = OpTypeInt 32 0
642%struct1 = OpTypeStruct %uint %uint
643%uint_ptr = OpTypePointer Function %uint
644%struct1_ptr = OpTypePointer Function %struct1
645%uint_0 = OpConstant %uint 0
646%uint_1 = OpConstant %uint 1
647%func = OpTypeFunction %void
648%1 = OpFunction %void None %func
649%2 = OpLabel
650%var = OpVariable %struct1_ptr Function
651%load = OpLoad %struct1 %var
652%3 = OpAccessChain %uint_ptr %var %uint_0
653OpStore %3 %uint_0
654%4 = OpAccessChain %uint_ptr %var %uint_1
655OpStore %4 %uint_0
656OpReturn
657OpFunctionEnd
658  )";
659
660  SinglePassRunAndMatch<ScalarReplacementPass>(text, true);
661}
662
663TEST_F(ScalarReplacementTest, ReplaceWholeLoadCopyMemoryAccess) {
664  const std::string text = R"(
665;
666; CHECK: [[uint:%\w+]] = OpTypeInt 32 0
667; CHECK: [[struct1:%\w+]] = OpTypeStruct [[uint]] [[uint]]
668; CHECK: [[uint_ptr:%\w+]] = OpTypePointer Function [[uint]]
669; CHECK: [[undef:%\w+]] = OpUndef [[uint]]
670; CHECK: [[var0:%\w+]] = OpVariable [[uint_ptr]] Function
671; CHECK: [[l0:%\w+]] = OpLoad [[uint]] [[var0]] Nontemporal
672; CHECK: OpCompositeConstruct [[struct1]] [[l0]] [[undef]]
673;
674OpCapability Shader
675OpCapability Linkage
676OpMemoryModel Logical GLSL450
677OpName %func "replace_whole_load_copy_memory_access"
678%void = OpTypeVoid
679%uint = OpTypeInt 32 0
680%struct1 = OpTypeStruct %uint %uint
681%uint_ptr = OpTypePointer Function %uint
682%struct1_ptr = OpTypePointer Function %struct1
683%uint_0 = OpConstant %uint 0
684%func = OpTypeFunction %void
685%1 = OpFunction %void None %func
686%2 = OpLabel
687%var = OpVariable %struct1_ptr Function
688%load = OpLoad %struct1 %var Nontemporal
689%3 = OpAccessChain %uint_ptr %var %uint_0
690OpStore %3 %uint_0
691OpReturn
692OpFunctionEnd
693  )";
694
695  SinglePassRunAndMatch<ScalarReplacementPass>(text, true);
696}
697
698TEST_F(ScalarReplacementTest, ReplaceWholeStore) {
699  const std::string text = R"(
700;
701; CHECK: [[uint:%\w+]] = OpTypeInt 32 0
702; CHECK: [[struct1:%\w+]] = OpTypeStruct [[uint]] [[uint]]
703; CHECK: [[uint_ptr:%\w+]] = OpTypePointer Function [[uint]]
704; CHECK: [[const:%\w+]] = OpConstant [[uint]] 0
705; CHECK: [[const_struct:%\w+]] = OpConstantComposite [[struct1]] [[const]] [[const]]
706; CHECK: [[var0:%\w+]] = OpVariable [[uint_ptr]] Function
707; CHECK: [[ex0:%\w+]] = OpCompositeExtract [[uint]] [[const_struct]] 0
708; CHECK: OpStore [[var0]] [[ex0]]
709;
710OpCapability Shader
711OpCapability Linkage
712OpMemoryModel Logical GLSL450
713OpName %func "replace_whole_store"
714%void = OpTypeVoid
715%uint = OpTypeInt 32 0
716%struct1 = OpTypeStruct %uint %uint
717%uint_ptr = OpTypePointer Function %uint
718%struct1_ptr = OpTypePointer Function %struct1
719%uint_0 = OpConstant %uint 0
720%const_struct = OpConstantComposite %struct1 %uint_0 %uint_0
721%func = OpTypeFunction %void
722%1 = OpFunction %void None %func
723%2 = OpLabel
724%var = OpVariable %struct1_ptr Function
725OpStore %var %const_struct
726%3 = OpAccessChain %uint_ptr %var %uint_0
727%4 = OpLoad %uint %3
728OpReturn
729OpFunctionEnd
730  )";
731
732  SinglePassRunAndMatch<ScalarReplacementPass>(text, true);
733}
734
735TEST_F(ScalarReplacementTest, ReplaceWholeStoreCopyMemoryAccess) {
736  const std::string text = R"(
737;
738; CHECK: [[uint:%\w+]] = OpTypeInt 32 0
739; CHECK: [[struct1:%\w+]] = OpTypeStruct [[uint]] [[uint]]
740; CHECK: [[uint_ptr:%\w+]] = OpTypePointer Function [[uint]]
741; CHECK: [[const:%\w+]] = OpConstant [[uint]] 0
742; CHECK: [[const_struct:%\w+]] = OpConstantComposite [[struct1]] [[const]] [[const]]
743; CHECK: [[var0:%\w+]] = OpVariable [[uint_ptr]] Function
744; CHECK-NOT: OpVariable
745; CHECK: [[ex0:%\w+]] = OpCompositeExtract [[uint]] [[const_struct]] 0
746; CHECK: OpStore [[var0]] [[ex0]] Aligned 4
747;
748OpCapability Shader
749OpCapability Linkage
750OpMemoryModel Logical GLSL450
751OpName %func "replace_whole_store_copy_memory_access"
752%void = OpTypeVoid
753%uint = OpTypeInt 32 0
754%struct1 = OpTypeStruct %uint %uint
755%uint_ptr = OpTypePointer Function %uint
756%struct1_ptr = OpTypePointer Function %struct1
757%uint_0 = OpConstant %uint 0
758%const_struct = OpConstantComposite %struct1 %uint_0 %uint_0
759%func = OpTypeFunction %void
760%1 = OpFunction %void None %func
761%2 = OpLabel
762%var = OpVariable %struct1_ptr Function
763OpStore %var %const_struct Aligned 4
764%3 = OpAccessChain %uint_ptr %var %uint_0
765%4 = OpLoad %uint %3
766OpReturn
767OpFunctionEnd
768  )";
769
770  SinglePassRunAndMatch<ScalarReplacementPass>(text, true);
771}
772
773TEST_F(ScalarReplacementTest, DontTouchVolatileLoad) {
774  const std::string text = R"(
775;
776; CHECK: [[struct:%\w+]] = OpTypeStruct
777; CHECK: [[struct_ptr:%\w+]] = OpTypePointer Function [[struct]]
778; CHECK: OpLabel
779; CHECK-NEXT: OpVariable [[struct_ptr]]
780; CHECK-NOT: OpVariable
781;
782OpCapability Shader
783OpCapability Linkage
784OpMemoryModel Logical GLSL450
785OpName %func "dont_touch_volatile_load"
786%void = OpTypeVoid
787%uint = OpTypeInt 32 0
788%struct1 = OpTypeStruct %uint
789%uint_ptr = OpTypePointer Function %uint
790%struct1_ptr = OpTypePointer Function %struct1
791%uint_0 = OpConstant %uint 0
792%func = OpTypeFunction %void
793%1 = OpFunction %void None %func
794%2 = OpLabel
795%var = OpVariable %struct1_ptr Function
796%3 = OpAccessChain %uint_ptr %var %uint_0
797%4 = OpLoad %uint %3 Volatile
798OpReturn
799OpFunctionEnd
800  )";
801
802  SinglePassRunAndMatch<ScalarReplacementPass>(text, true);
803}
804
805TEST_F(ScalarReplacementTest, DontTouchVolatileStore) {
806  const std::string text = R"(
807;
808; CHECK: [[struct:%\w+]] = OpTypeStruct
809; CHECK: [[struct_ptr:%\w+]] = OpTypePointer Function [[struct]]
810; CHECK: OpLabel
811; CHECK-NEXT: OpVariable [[struct_ptr]]
812; CHECK-NOT: OpVariable
813;
814OpCapability Shader
815OpCapability Linkage
816OpMemoryModel Logical GLSL450
817OpName %func "dont_touch_volatile_store"
818%void = OpTypeVoid
819%uint = OpTypeInt 32 0
820%struct1 = OpTypeStruct %uint
821%uint_ptr = OpTypePointer Function %uint
822%struct1_ptr = OpTypePointer Function %struct1
823%uint_0 = OpConstant %uint 0
824%func = OpTypeFunction %void
825%1 = OpFunction %void None %func
826%2 = OpLabel
827%var = OpVariable %struct1_ptr Function
828%3 = OpAccessChain %uint_ptr %var %uint_0
829OpStore %3 %uint_0 Volatile
830OpReturn
831OpFunctionEnd
832  )";
833
834  SinglePassRunAndMatch<ScalarReplacementPass>(text, true);
835}
836
837TEST_F(ScalarReplacementTest, DontTouchSpecNonFunctionVariable) {
838  const std::string text = R"(
839;
840; CHECK: [[struct:%\w+]] = OpTypeStruct
841; CHECK: [[struct_ptr:%\w+]] = OpTypePointer Uniform [[struct]]
842; CHECK: OpConstant
843; CHECK-NEXT: OpVariable [[struct_ptr]]
844; CHECK-NOT: OpVariable
845;
846OpCapability Shader
847OpCapability Linkage
848OpMemoryModel Logical GLSL450
849OpName %func "dont_touch_spec_constant_access_chain"
850%void = OpTypeVoid
851%uint = OpTypeInt 32 0
852%struct1 = OpTypeStruct %uint
853%uint_ptr = OpTypePointer Uniform %uint
854%struct1_ptr = OpTypePointer Uniform %struct1
855%uint_0 = OpConstant %uint 0
856%var = OpVariable %struct1_ptr Uniform
857%func = OpTypeFunction %void
858%1 = OpFunction %void None %func
859%2 = OpLabel
860%3 = OpAccessChain %uint_ptr %var %uint_0
861OpStore %3 %uint_0 Volatile
862OpReturn
863OpFunctionEnd
864  )";
865
866  SinglePassRunAndMatch<ScalarReplacementPass>(text, true);
867}
868
869TEST_F(ScalarReplacementTest, DontTouchSpecConstantAccessChain) {
870  const std::string text = R"(
871;
872; CHECK: [[array:%\w+]] = OpTypeArray
873; CHECK: [[array_ptr:%\w+]] = OpTypePointer Function [[array]]
874; CHECK: OpLabel
875; CHECK-NEXT: OpVariable [[array_ptr]]
876; CHECK-NOT: OpVariable
877;
878OpCapability Shader
879OpCapability Linkage
880OpMemoryModel Logical GLSL450
881OpName %func "dont_touch_spec_constant_access_chain"
882%void = OpTypeVoid
883%uint = OpTypeInt 32 0
884%uint_1 = OpConstant %uint 1
885%array = OpTypeArray %uint %uint_1
886%uint_ptr = OpTypePointer Function %uint
887%array_ptr = OpTypePointer Function %array
888%uint_0 = OpConstant %uint 0
889%spec_const = OpSpecConstant %uint 0
890%func = OpTypeFunction %void
891%1 = OpFunction %void None %func
892%2 = OpLabel
893%var = OpVariable %array_ptr Function
894%3 = OpAccessChain %uint_ptr %var %spec_const
895OpStore %3 %uint_0 Volatile
896OpReturn
897OpFunctionEnd
898  )";
899
900  SinglePassRunAndMatch<ScalarReplacementPass>(text, true);
901}
902
903TEST_F(ScalarReplacementTest, NoPartialAccesses) {
904  const std::string text = R"(
905;
906; CHECK: [[uint:%\w+]] = OpTypeInt 32 0
907; CHECK: [[uint_ptr:%\w+]] = OpTypePointer Function [[uint]]
908; CHECK: OpLabel
909; CHECK-NOT: OpVariable
910;
911OpCapability Shader
912OpCapability Linkage
913OpMemoryModel Logical GLSL450
914OpName %func "no_partial_accesses"
915%void = OpTypeVoid
916%uint = OpTypeInt 32 0
917%struct1 = OpTypeStruct %uint
918%uint_ptr = OpTypePointer Function %uint
919%struct1_ptr = OpTypePointer Function %struct1
920%const = OpConstantNull %struct1
921%func = OpTypeFunction %void
922%1 = OpFunction %void None %func
923%2 = OpLabel
924%var = OpVariable %struct1_ptr Function
925OpStore %var %const
926OpReturn
927OpFunctionEnd
928  )";
929
930  SinglePassRunAndMatch<ScalarReplacementPass>(text, true);
931}
932
933TEST_F(ScalarReplacementTest, DontTouchPtrAccessChain) {
934  const std::string text = R"(
935;
936; CHECK: [[struct:%\w+]] = OpTypeStruct
937; CHECK: [[struct_ptr:%\w+]] = OpTypePointer Function [[struct]]
938; CHECK: OpLabel
939; CHECK-NEXT: OpVariable [[struct_ptr]]
940; CHECK-NOT: OpVariable
941;
942OpCapability Shader
943OpCapability Linkage
944OpMemoryModel Logical GLSL450
945OpName %func "dont_touch_ptr_access_chain"
946%void = OpTypeVoid
947%uint = OpTypeInt 32 0
948%struct1 = OpTypeStruct %uint
949%uint_ptr = OpTypePointer Function %uint
950%struct1_ptr = OpTypePointer Function %struct1
951%uint_0 = OpConstant %uint 0
952%func = OpTypeFunction %void
953%1 = OpFunction %void None %func
954%2 = OpLabel
955%var = OpVariable %struct1_ptr Function
956%3 = OpPtrAccessChain %uint_ptr %var %uint_0 %uint_0
957OpStore %3 %uint_0
958%4 = OpAccessChain %uint_ptr %var %uint_0
959OpStore %4 %uint_0
960OpReturn
961OpFunctionEnd
962  )";
963
964  SinglePassRunAndMatch<ScalarReplacementPass>(text, false);
965}
966
967TEST_F(ScalarReplacementTest, DontTouchInBoundsPtrAccessChain) {
968  const std::string text = R"(
969;
970; CHECK: [[struct:%\w+]] = OpTypeStruct
971; CHECK: [[struct_ptr:%\w+]] = OpTypePointer Function [[struct]]
972; CHECK: OpLabel
973; CHECK-NEXT: OpVariable [[struct_ptr]]
974; CHECK-NOT: OpVariable
975;
976OpCapability Shader
977OpCapability Linkage
978OpMemoryModel Logical GLSL450
979OpName %func "dont_touch_in_bounds_ptr_access_chain"
980%void = OpTypeVoid
981%uint = OpTypeInt 32 0
982%struct1 = OpTypeStruct %uint
983%uint_ptr = OpTypePointer Function %uint
984%struct1_ptr = OpTypePointer Function %struct1
985%uint_0 = OpConstant %uint 0
986%func = OpTypeFunction %void
987%1 = OpFunction %void None %func
988%2 = OpLabel
989%var = OpVariable %struct1_ptr Function
990%3 = OpInBoundsPtrAccessChain %uint_ptr %var %uint_0 %uint_0
991OpStore %3 %uint_0
992%4 = OpInBoundsAccessChain %uint_ptr %var %uint_0
993OpStore %4 %uint_0
994OpReturn
995OpFunctionEnd
996  )";
997
998  SinglePassRunAndMatch<ScalarReplacementPass>(text, false);
999}
1000
1001TEST_F(ScalarReplacementTest, DonTouchAliasedDecoration) {
1002  const std::string text = R"(
1003;
1004; CHECK: [[struct:%\w+]] = OpTypeStruct
1005; CHECK: [[struct_ptr:%\w+]] = OpTypePointer Function [[struct]]
1006; CHECK: OpLabel
1007; CHECK-NEXT: OpVariable [[struct_ptr]]
1008; CHECK-NOT: OpVariable
1009;
1010OpCapability Shader
1011OpCapability Linkage
1012OpMemoryModel Logical GLSL450
1013OpName %func "aliased"
1014OpDecorate %var Aliased
1015%void = OpTypeVoid
1016%uint = OpTypeInt 32 0
1017%struct1 = OpTypeStruct %uint
1018%uint_ptr = OpTypePointer Function %uint
1019%struct1_ptr = OpTypePointer Function %struct1
1020%uint_0 = OpConstant %uint 0
1021%func = OpTypeFunction %void
1022%1 = OpFunction %void None %func
1023%2 = OpLabel
1024%var = OpVariable %struct1_ptr Function
1025%3 = OpAccessChain %uint_ptr %var %uint_0
1026%4 = OpLoad %uint %3
1027OpReturn
1028OpFunctionEnd
1029  )";
1030
1031  SinglePassRunAndMatch<ScalarReplacementPass>(text, true);
1032}
1033
1034TEST_F(ScalarReplacementTest, CopyRestrictDecoration) {
1035  const std::string text = R"(
1036;
1037; CHECK: OpName
1038; CHECK-NEXT: OpDecorate [[var0:%\w+]] Restrict
1039; CHECK-NEXT: OpDecorate [[var1:%\w+]] Restrict
1040; CHECK: [[int:%\w+]] = OpTypeInt
1041; CHECK: [[struct:%\w+]] = OpTypeStruct
1042; CHECK: [[int_ptr:%\w+]] = OpTypePointer Function [[int]]
1043; CHECK: [[struct_ptr:%\w+]] = OpTypePointer Function [[struct]]
1044; CHECK: OpLabel
1045; CHECK-NEXT: [[var1]] = OpVariable [[int_ptr]]
1046; CHECK-NEXT: [[var0]] = OpVariable [[int_ptr]]
1047; CHECK-NOT: OpVariable [[struct_ptr]]
1048;
1049OpCapability Shader
1050OpCapability Linkage
1051OpMemoryModel Logical GLSL450
1052OpName %func "restrict"
1053OpDecorate %var Restrict
1054%void = OpTypeVoid
1055%uint = OpTypeInt 32 0
1056%struct1 = OpTypeStruct %uint %uint
1057%uint_ptr = OpTypePointer Function %uint
1058%struct1_ptr = OpTypePointer Function %struct1
1059%uint_0 = OpConstant %uint 0
1060%uint_1 = OpConstant %uint 1
1061%func = OpTypeFunction %void
1062%1 = OpFunction %void None %func
1063%2 = OpLabel
1064%var = OpVariable %struct1_ptr Function
1065%3 = OpAccessChain %uint_ptr %var %uint_0
1066%4 = OpLoad %uint %3
1067%5 = OpAccessChain %uint_ptr %var %uint_1
1068%6 = OpLoad %uint %5
1069OpReturn
1070OpFunctionEnd
1071  )";
1072
1073  SinglePassRunAndMatch<ScalarReplacementPass>(text, true);
1074}
1075
1076TEST_F(ScalarReplacementTest, DontClobberDecoratesOnSubtypes) {
1077  const std::string text = R"(
1078;
1079; CHECK: OpDecorate [[array:%\w+]] ArrayStride 1
1080; CHECK: [[uint:%\w+]] = OpTypeInt 32 0
1081; CHECK: [[array]] = OpTypeArray [[uint]]
1082; CHECK: [[array_ptr:%\w+]] = OpTypePointer Function [[array]]
1083; CHECK: OpLabel
1084; CHECK-NEXT: OpVariable [[array_ptr]] Function
1085; CHECK-NOT: OpVariable
1086;
1087OpCapability Shader
1088OpCapability Linkage
1089OpMemoryModel Logical GLSL450
1090OpName %func "array_stride"
1091OpDecorate %array ArrayStride 1
1092%void = OpTypeVoid
1093%uint = OpTypeInt 32 0
1094%uint_1 = OpConstant %uint 1
1095%array = OpTypeArray %uint %uint_1
1096%struct1 = OpTypeStruct %array
1097%uint_ptr = OpTypePointer Function %uint
1098%struct1_ptr = OpTypePointer Function %struct1
1099%uint_0 = OpConstant %uint 0
1100%func = OpTypeFunction %void %uint
1101%1 = OpFunction %void None %func
1102%param = OpFunctionParameter %uint
1103%2 = OpLabel
1104%var = OpVariable %struct1_ptr Function
1105%3 = OpAccessChain %uint_ptr %var %uint_0 %param
1106%4 = OpLoad %uint %3
1107OpReturn
1108OpFunctionEnd
1109  )";
1110
1111  SinglePassRunAndMatch<ScalarReplacementPass>(text, true);
1112}
1113
1114TEST_F(ScalarReplacementTest, DontCopyMemberDecorate) {
1115  const std::string text = R"(
1116;
1117; CHECK-NOT: OpDecorate
1118; CHECK: [[uint:%\w+]] = OpTypeInt 32 0
1119; CHECK: [[struct:%\w+]] = OpTypeStruct [[uint]]
1120; CHECK: [[uint_ptr:%\w+]] = OpTypePointer Function [[uint]]
1121; CHECK: [[struct_ptr:%\w+]] = OpTypePointer Function [[struct]]
1122; CHECK: OpLabel
1123; CHECK-NEXT: OpVariable [[uint_ptr]] Function
1124; CHECK-NOT: OpVariable
1125;
1126OpCapability Shader
1127OpCapability Linkage
1128OpMemoryModel Logical GLSL450
1129OpName %func "member_decorate"
1130OpMemberDecorate %struct1 0 Offset 1
1131%void = OpTypeVoid
1132%uint = OpTypeInt 32 0
1133%uint_1 = OpConstant %uint 1
1134%struct1 = OpTypeStruct %uint
1135%uint_ptr = OpTypePointer Function %uint
1136%struct1_ptr = OpTypePointer Function %struct1
1137%uint_0 = OpConstant %uint 0
1138%func = OpTypeFunction %void %uint
1139%1 = OpFunction %void None %func
1140%2 = OpLabel
1141%var = OpVariable %struct1_ptr Function
1142%3 = OpAccessChain %uint_ptr %var %uint_0
1143%4 = OpLoad %uint %3
1144OpReturn
1145OpFunctionEnd
1146  )";
1147
1148  SinglePassRunAndMatch<ScalarReplacementPass>(text, true);
1149}
1150
1151TEST_F(ScalarReplacementTest, NoPartialAccesses2) {
1152  const std::string text = R"(
1153;
1154; CHECK: [[float:%\w+]] = OpTypeFloat 32
1155; CHECK: [[float_ptr:%\w+]] = OpTypePointer Function [[float]]
1156; CHECK: OpVariable [[float_ptr]] Function
1157; CHECK: OpVariable [[float_ptr]] Function
1158; CHECK: OpVariable [[float_ptr]] Function
1159; CHECK: OpVariable [[float_ptr]] Function
1160; CHECK: OpVariable [[float_ptr]] Function
1161; CHECK: OpVariable [[float_ptr]] Function
1162; CHECK: OpVariable [[float_ptr]] Function
1163; CHECK-NOT: OpVariable
1164;
1165OpCapability Shader
1166%1 = OpExtInstImport "GLSL.std.450"
1167OpMemoryModel Logical GLSL450
1168OpEntryPoint Fragment %main "main" %fo
1169OpExecutionMode %main OriginUpperLeft
1170OpSource GLSL 430
1171OpName %main "main"
1172OpName %S "S"
1173OpMemberName %S 0 "x"
1174OpMemberName %S 1 "y"
1175OpName %ts1 "ts1"
1176OpName %S_0 "S"
1177OpMemberName %S_0 0 "x"
1178OpMemberName %S_0 1 "y"
1179OpName %U_t "U_t"
1180OpMemberName %U_t 0 "g_s1"
1181OpMemberName %U_t 1 "g_s2"
1182OpMemberName %U_t 2 "g_s3"
1183OpName %_ ""
1184OpName %ts2 "ts2"
1185OpName %_Globals_ "_Globals_"
1186OpMemberName %_Globals_ 0 "g_b"
1187OpName %__0 ""
1188OpName %ts3 "ts3"
1189OpName %ts4 "ts4"
1190OpName %fo "fo"
1191OpMemberDecorate %S_0 0 Offset 0
1192OpMemberDecorate %S_0 1 Offset 4
1193OpMemberDecorate %U_t 0 Offset 0
1194OpMemberDecorate %U_t 1 Offset 8
1195OpMemberDecorate %U_t 2 Offset 16
1196OpDecorate %U_t BufferBlock
1197OpDecorate %_ DescriptorSet 0
1198OpMemberDecorate %_Globals_ 0 Offset 0
1199OpDecorate %_Globals_ Block
1200OpDecorate %__0 DescriptorSet 0
1201OpDecorate %__0 Binding 0
1202OpDecorate %fo Location 0
1203%void = OpTypeVoid
1204%15 = OpTypeFunction %void
1205%float = OpTypeFloat 32
1206%S = OpTypeStruct %float %float
1207%_ptr_Function_S = OpTypePointer Function %S
1208%S_0 = OpTypeStruct %float %float
1209%U_t = OpTypeStruct %S_0 %S_0 %S_0
1210%_ptr_Uniform_U_t = OpTypePointer Uniform %U_t
1211%_ = OpVariable %_ptr_Uniform_U_t Uniform
1212%int = OpTypeInt 32 1
1213%int_0 = OpConstant %int 0
1214%_ptr_Uniform_S_0 = OpTypePointer Uniform %S_0
1215%_ptr_Function_float = OpTypePointer Function %float
1216%int_1 = OpConstant %int 1
1217%uint = OpTypeInt 32 0
1218%_Globals_ = OpTypeStruct %uint
1219%_ptr_Uniform__Globals_ = OpTypePointer Uniform %_Globals_
1220%__0 = OpVariable %_ptr_Uniform__Globals_ Uniform
1221%_ptr_Uniform_uint = OpTypePointer Uniform %uint
1222%bool = OpTypeBool
1223%uint_0 = OpConstant %uint 0
1224%_ptr_Output_float = OpTypePointer Output %float
1225%fo = OpVariable %_ptr_Output_float Output
1226%main = OpFunction %void None %15
1227%30 = OpLabel
1228%ts1 = OpVariable %_ptr_Function_S Function
1229%ts2 = OpVariable %_ptr_Function_S Function
1230%ts3 = OpVariable %_ptr_Function_S Function
1231%ts4 = OpVariable %_ptr_Function_S Function
1232%31 = OpAccessChain %_ptr_Uniform_S_0 %_ %int_0
1233%32 = OpLoad %S_0 %31
1234%33 = OpCompositeExtract %float %32 0
1235%34 = OpAccessChain %_ptr_Function_float %ts1 %int_0
1236OpStore %34 %33
1237%35 = OpCompositeExtract %float %32 1
1238%36 = OpAccessChain %_ptr_Function_float %ts1 %int_1
1239OpStore %36 %35
1240%37 = OpAccessChain %_ptr_Uniform_S_0 %_ %int_1
1241%38 = OpLoad %S_0 %37
1242%39 = OpCompositeExtract %float %38 0
1243%40 = OpAccessChain %_ptr_Function_float %ts2 %int_0
1244OpStore %40 %39
1245%41 = OpCompositeExtract %float %38 1
1246%42 = OpAccessChain %_ptr_Function_float %ts2 %int_1
1247OpStore %42 %41
1248%43 = OpAccessChain %_ptr_Uniform_uint %__0 %int_0
1249%44 = OpLoad %uint %43
1250%45 = OpINotEqual %bool %44 %uint_0
1251OpSelectionMerge %46 None
1252OpBranchConditional %45 %47 %48
1253%47 = OpLabel
1254%49 = OpLoad %S %ts1
1255OpStore %ts3 %49
1256OpBranch %46
1257%48 = OpLabel
1258%50 = OpLoad %S %ts2
1259OpStore %ts3 %50
1260OpBranch %46
1261%46 = OpLabel
1262%51 = OpLoad %S %ts3
1263OpStore %ts4 %51
1264%52 = OpAccessChain %_ptr_Function_float %ts4 %int_1
1265%53 = OpLoad %float %52
1266OpStore %fo %53
1267OpReturn
1268OpFunctionEnd
1269  )";
1270
1271  SinglePassRunAndMatch<ScalarReplacementPass>(text, true);
1272}
1273
1274TEST_F(ScalarReplacementTest, ReplaceWholeLoadAndStore) {
1275  const std::string text = R"(
1276;
1277; CHECK: [[uint:%\w+]] = OpTypeInt 32 0
1278; CHECK: [[struct1:%\w+]] = OpTypeStruct [[uint]] [[uint]]
1279; CHECK: [[uint_ptr:%\w+]] = OpTypePointer Function [[uint]]
1280; CHECK: [[const:%\w+]] = OpConstant [[uint]] 0
1281; CHECK: [[undef:%\w+]] = OpUndef [[uint]]
1282; CHECK: [[var0:%\w+]] = OpVariable [[uint_ptr]] Function
1283; CHECK: [[var1:%\w+]] = OpVariable [[uint_ptr]] Function
1284; CHECK-NOT: OpVariable
1285; CHECK: [[l0:%\w+]] = OpLoad [[uint]] [[var0]]
1286; CHECK: [[c0:%\w+]] = OpCompositeConstruct [[struct1]] [[l0]] [[undef]]
1287; CHECK: [[e0:%\w+]] = OpCompositeExtract [[uint]] [[c0]] 0
1288; CHECK: OpStore [[var1]] [[e0]]
1289; CHECK: [[l1:%\w+]] = OpLoad [[uint]] [[var1]]
1290; CHECK: [[c1:%\w+]] = OpCompositeConstruct [[struct1]] [[l1]] [[undef]]
1291; CHECK: [[e1:%\w+]] = OpCompositeExtract [[uint]] [[c1]] 0
1292;
1293OpCapability Shader
1294OpCapability Linkage
1295OpMemoryModel Logical GLSL450
1296OpName %func "replace_whole_load"
1297%void = OpTypeVoid
1298%uint = OpTypeInt 32 0
1299%struct1 = OpTypeStruct %uint %uint
1300%uint_ptr = OpTypePointer Function %uint
1301%struct1_ptr = OpTypePointer Function %struct1
1302%uint_0 = OpConstant %uint 0
1303%uint_1 = OpConstant %uint 1
1304%func = OpTypeFunction %void
1305%1 = OpFunction %void None %func
1306%2 = OpLabel
1307%var2 = OpVariable %struct1_ptr Function
1308%var1 = OpVariable %struct1_ptr Function
1309%load1 = OpLoad %struct1 %var1
1310OpStore %var2 %load1
1311%load2 = OpLoad %struct1 %var2
1312%3 = OpCompositeExtract %uint %load2 0
1313OpReturn
1314OpFunctionEnd
1315  )";
1316
1317  SinglePassRunAndMatch<ScalarReplacementPass>(text, true);
1318}
1319
1320TEST_F(ScalarReplacementTest, ReplaceWholeLoadAndStore2) {
1321  // TODO: We can improve this case by ensuring that |var2| is processed first.
1322  const std::string text = R"(
1323;
1324; CHECK: [[uint:%\w+]] = OpTypeInt 32 0
1325; CHECK: [[struct1:%\w+]] = OpTypeStruct [[uint]] [[uint]]
1326; CHECK: [[uint_ptr:%\w+]] = OpTypePointer Function [[uint]]
1327; CHECK: [[const:%\w+]] = OpConstant [[uint]] 0
1328; CHECK: [[undef:%\w+]] = OpUndef [[uint]]
1329; CHECK: [[var1:%\w+]] = OpVariable [[uint_ptr]] Function
1330; CHECK: [[var0a:%\w+]] = OpVariable [[uint_ptr]] Function
1331; CHECK: [[var0b:%\w+]] = OpVariable [[uint_ptr]] Function
1332; CHECK-NOT: OpVariable
1333; CHECK: [[l0a:%\w+]] = OpLoad [[uint]] [[var0a]]
1334; CHECK: [[l0b:%\w+]] = OpLoad [[uint]] [[var0b]]
1335; CHECK: [[c0:%\w+]] = OpCompositeConstruct [[struct1]] [[l0b]] [[l0a]]
1336; CHECK: [[e0:%\w+]] = OpCompositeExtract [[uint]] [[c0]] 0
1337; CHECK: OpStore [[var1]] [[e0]]
1338; CHECK: [[l1:%\w+]] = OpLoad [[uint]] [[var1]]
1339; CHECK: [[c1:%\w+]] = OpCompositeConstruct [[struct1]] [[l1]] [[undef]]
1340; CHECK: [[e1:%\w+]] = OpCompositeExtract [[uint]] [[c1]] 0
1341;
1342OpCapability Shader
1343OpCapability Linkage
1344OpMemoryModel Logical GLSL450
1345OpName %func "replace_whole_load"
1346%void = OpTypeVoid
1347%uint = OpTypeInt 32 0
1348%struct1 = OpTypeStruct %uint %uint
1349%uint_ptr = OpTypePointer Function %uint
1350%struct1_ptr = OpTypePointer Function %struct1
1351%uint_0 = OpConstant %uint 0
1352%uint_1 = OpConstant %uint 1
1353%func = OpTypeFunction %void
1354%1 = OpFunction %void None %func
1355%2 = OpLabel
1356%var1 = OpVariable %struct1_ptr Function
1357%var2 = OpVariable %struct1_ptr Function
1358%load1 = OpLoad %struct1 %var1
1359OpStore %var2 %load1
1360%load2 = OpLoad %struct1 %var2
1361%3 = OpCompositeExtract %uint %load2 0
1362OpReturn
1363OpFunctionEnd
1364  )";
1365
1366  SinglePassRunAndMatch<ScalarReplacementPass>(text, true);
1367}
1368
1369TEST_F(ScalarReplacementTest, CreateAmbiguousNullConstant1) {
1370  const std::string text = R"(
1371;
1372; CHECK: [[uint:%\w+]] = OpTypeInt 32 0
1373; CHECK: [[struct1:%\w+]] = OpTypeStruct [[uint]] [[struct_member:%\w+]]
1374; CHECK: [[uint_ptr:%\w+]] = OpTypePointer Function [[uint]]
1375; CHECK: [[const:%\w+]] = OpConstant [[uint]] 0
1376; CHECK: [[undef:%\w+]] = OpUndef [[struct_member]]
1377; CHECK: [[var0a:%\w+]] = OpVariable [[uint_ptr]] Function
1378; CHECK: [[var1:%\w+]] = OpVariable [[uint_ptr]] Function
1379; CHECK: [[var0b:%\w+]] = OpVariable [[uint_ptr]] Function
1380; CHECK-NOT: OpVariable
1381; CHECK: OpStore [[var1]]
1382; CHECK: [[l1:%\w+]] = OpLoad [[uint]] [[var1]]
1383; CHECK: [[c1:%\w+]] = OpCompositeConstruct [[struct1]] [[l1]] [[undef]]
1384; CHECK: [[e1:%\w+]] = OpCompositeExtract [[uint]] [[c1]] 0
1385;
1386OpCapability Shader
1387OpCapability Linkage
1388OpMemoryModel Logical GLSL450
1389OpName %func "replace_whole_load"
1390%void = OpTypeVoid
1391%uint = OpTypeInt 32 0
1392%struct2 = OpTypeStruct %uint
1393%struct3 = OpTypeStruct %uint
1394%struct1 = OpTypeStruct %uint %struct2
1395%uint_ptr = OpTypePointer Function %uint
1396%struct1_ptr = OpTypePointer Function %struct1
1397%uint_0 = OpConstant %uint 0
1398%uint_1 = OpConstant %uint 1
1399%func = OpTypeFunction %void
1400%1 = OpFunction %void None %func
1401%2 = OpLabel
1402%var1 = OpVariable %struct1_ptr Function
1403%var2 = OpVariable %struct1_ptr Function
1404%load1 = OpLoad %struct1 %var1
1405OpStore %var2 %load1
1406%load2 = OpLoad %struct1 %var2
1407%3 = OpCompositeExtract %uint %load2 0
1408OpReturn
1409OpFunctionEnd
1410  )";
1411
1412  SinglePassRunAndMatch<ScalarReplacementPass>(text, true);
1413}
1414
1415TEST_F(ScalarReplacementTest, SpecConstantArray) {
1416  const std::string text = R"(
1417; CHECK: [[int:%\w+]] = OpTypeInt
1418; CHECK: [[spec_const:%\w+]] = OpSpecConstant [[int]] 4
1419; CHECK: [[spec_op:%\w+]] = OpSpecConstantOp [[int]] IAdd [[spec_const]] [[spec_const]]
1420; CHECK: [[array1:%\w+]] = OpTypeArray [[int]] [[spec_const]]
1421; CHECK: [[array2:%\w+]] = OpTypeArray [[int]] [[spec_op]]
1422; CHECK: [[ptr_array1:%\w+]] = OpTypePointer Function [[array1]]
1423; CHECK: [[ptr_array2:%\w+]] = OpTypePointer Function [[array2]]
1424; CHECK: OpLabel
1425; CHECK-NEXT: OpVariable [[ptr_array1]] Function
1426; CHECK-NEXT: OpVariable [[ptr_array2]] Function
1427; CHECK-NOT: OpVariable
1428OpCapability Shader
1429OpCapability Linkage
1430OpMemoryModel Logical GLSL450
1431%void = OpTypeVoid
1432%void_fn = OpTypeFunction %void
1433%int = OpTypeInt 32 0
1434%spec_const = OpSpecConstant %int 4
1435%spec_op = OpSpecConstantOp %int IAdd %spec_const %spec_const
1436%array_1 = OpTypeArray %int %spec_const
1437%array_2 = OpTypeArray %int %spec_op
1438%ptr_array_1_Function = OpTypePointer Function %array_1
1439%ptr_array_2_Function = OpTypePointer Function %array_2
1440%func = OpFunction %void None %void_fn
1441%1 = OpLabel
1442%var_1 = OpVariable %ptr_array_1_Function Function
1443%var_2 = OpVariable %ptr_array_2_Function Function
1444OpReturn
1445OpFunctionEnd
1446)";
1447
1448  SinglePassRunAndMatch<ScalarReplacementPass>(text, true);
1449}
1450
1451TEST_F(ScalarReplacementTest, CreateAmbiguousNullConstant2) {
1452  const std::string text = R"(
1453;
1454; CHECK: [[uint:%\w+]] = OpTypeInt 32 0
1455; CHECK: [[struct1:%\w+]] = OpTypeStruct [[uint]] [[struct_member:%\w+]]
1456; CHECK: [[uint_ptr:%\w+]] = OpTypePointer Function [[uint]]
1457; CHECK: [[const:%\w+]] = OpConstant [[uint]] 0
1458; CHECK: [[undef:%\w+]] = OpUndef [[struct_member]]
1459; CHECK: [[var0a:%\w+]] = OpVariable [[uint_ptr]] Function
1460; CHECK: [[var1:%\w+]] = OpVariable [[uint_ptr]] Function
1461; CHECK: [[var0b:%\w+]] = OpVariable [[uint_ptr]] Function
1462; CHECK: OpStore [[var1]]
1463; CHECK: [[l1:%\w+]] = OpLoad [[uint]] [[var1]]
1464; CHECK: [[c1:%\w+]] = OpCompositeConstruct [[struct1]] [[l1]] [[undef]]
1465; CHECK: [[e1:%\w+]] = OpCompositeExtract [[uint]] [[c1]] 0
1466;
1467OpCapability Shader
1468OpCapability Linkage
1469OpMemoryModel Logical GLSL450
1470OpName %func "replace_whole_load"
1471%void = OpTypeVoid
1472%uint = OpTypeInt 32 0
1473%struct3 = OpTypeStruct %uint
1474%struct2 = OpTypeStruct %uint
1475%struct1 = OpTypeStruct %uint %struct2
1476%uint_ptr = OpTypePointer Function %uint
1477%struct1_ptr = OpTypePointer Function %struct1
1478%uint_0 = OpConstant %uint 0
1479%uint_1 = OpConstant %uint 1
1480%func = OpTypeFunction %void
1481%1 = OpFunction %void None %func
1482%2 = OpLabel
1483%var1 = OpVariable %struct1_ptr Function
1484%var2 = OpVariable %struct1_ptr Function
1485%load1 = OpLoad %struct1 %var1
1486OpStore %var2 %load1
1487%load2 = OpLoad %struct1 %var2
1488%3 = OpCompositeExtract %uint %load2 0
1489OpReturn
1490OpFunctionEnd
1491  )";
1492
1493  SinglePassRunAndMatch<ScalarReplacementPass>(text, true);
1494}
1495
1496// Test that a struct of size 4 is not replaced when there is a limit of 2.
1497TEST_F(ScalarReplacementTest, TestLimit) {
1498  const std::string text = R"(
1499OpCapability Shader
1500OpCapability Linkage
1501OpMemoryModel Logical GLSL450
1502OpName %6 "simple_struct"
1503%1 = OpTypeVoid
1504%2 = OpTypeInt 32 0
1505%3 = OpTypeStruct %2 %2 %2 %2
1506%4 = OpTypePointer Function %3
1507%5 = OpTypePointer Function %2
1508%6 = OpTypeFunction %2
1509%7 = OpConstantNull %3
1510%8 = OpConstant %2 0
1511%9 = OpConstant %2 1
1512%10 = OpConstant %2 2
1513%11 = OpConstant %2 3
1514%12 = OpFunction %2 None %6
1515%13 = OpLabel
1516%14 = OpVariable %4 Function %7
1517%15 = OpInBoundsAccessChain %5 %14 %8
1518%16 = OpLoad %2 %15
1519%17 = OpAccessChain %5 %14 %10
1520%18 = OpLoad %2 %17
1521%19 = OpIAdd %2 %16 %18
1522OpReturnValue %19
1523OpFunctionEnd
1524  )";
1525
1526  auto result =
1527      SinglePassRunAndDisassemble<ScalarReplacementPass>(text, true, false, 2);
1528  EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
1529}
1530
1531// Test that a struct of size 4 is replaced when there is a limit of 0 (no
1532// limit).  This is the same spir-v as a test above, so we do not check that it
1533// is correctly transformed.  We leave that to the test above.
1534TEST_F(ScalarReplacementTest, TestUnimited) {
1535  const std::string text = R"(
1536OpCapability Shader
1537OpCapability Linkage
1538OpMemoryModel Logical GLSL450
1539OpName %6 "simple_struct"
1540%1 = OpTypeVoid
1541%2 = OpTypeInt 32 0
1542%3 = OpTypeStruct %2 %2 %2 %2
1543%4 = OpTypePointer Function %3
1544%5 = OpTypePointer Function %2
1545%6 = OpTypeFunction %2
1546%7 = OpConstantNull %3
1547%8 = OpConstant %2 0
1548%9 = OpConstant %2 1
1549%10 = OpConstant %2 2
1550%11 = OpConstant %2 3
1551%12 = OpFunction %2 None %6
1552%13 = OpLabel
1553%14 = OpVariable %4 Function %7
1554%15 = OpInBoundsAccessChain %5 %14 %8
1555%16 = OpLoad %2 %15
1556%17 = OpAccessChain %5 %14 %10
1557%18 = OpLoad %2 %17
1558%19 = OpIAdd %2 %16 %18
1559OpReturnValue %19
1560OpFunctionEnd
1561  )";
1562
1563  auto result =
1564      SinglePassRunAndDisassemble<ScalarReplacementPass>(text, true, false, 0);
1565  EXPECT_EQ(Pass::Status::SuccessWithChange, std::get<1>(result));
1566}
1567
1568TEST_F(ScalarReplacementTest, AmbigousPointer) {
1569  const std::string text = R"(
1570; CHECK: [[s1:%\w+]] = OpTypeStruct %uint
1571; CHECK: [[s2:%\w+]] = OpTypeStruct %uint
1572; CHECK: [[s3:%\w+]] = OpTypeStruct [[s2]]
1573; CHECK: [[s3_const:%\w+]] = OpConstantComposite [[s3]]
1574; CHECK: [[s2_ptr:%\w+]] = OpTypePointer Function [[s2]]
1575; CHECK: OpCompositeExtract [[s2]] [[s3_const]]
1576
1577               OpCapability Shader
1578          %1 = OpExtInstImport "GLSL.std.450"
1579               OpMemoryModel Logical GLSL450
1580               OpEntryPoint Fragment %2 "main"
1581               OpExecutionMode %2 OriginUpperLeft
1582               OpSource ESSL 310
1583       %void = OpTypeVoid
1584          %5 = OpTypeFunction %void
1585       %uint = OpTypeInt 32 0
1586  %_struct_7 = OpTypeStruct %uint
1587  %_struct_8 = OpTypeStruct %uint
1588  %_struct_9 = OpTypeStruct %_struct_8
1589     %uint_1 = OpConstant %uint 1
1590         %11 = OpConstantComposite %_struct_8 %uint_1
1591         %12 = OpConstantComposite %_struct_9 %11
1592%_ptr_Function__struct_9 = OpTypePointer Function %_struct_9
1593%_ptr_Function__struct_7 = OpTypePointer Function %_struct_7
1594          %2 = OpFunction %void None %5
1595         %15 = OpLabel
1596        %var = OpVariable %_ptr_Function__struct_9 Function
1597               OpStore %var %12
1598         %ld = OpLoad %_struct_9 %var
1599         %ex = OpCompositeExtract %_struct_8 %ld 0
1600               OpReturn
1601               OpFunctionEnd
1602  )";
1603
1604  SinglePassRunAndMatch<ScalarReplacementPass>(text, true);
1605}
1606
1607// Test that scalar replacement does not crash when there is an OpAccessChain
1608// with no index.  If we choose to handle this case in the future, then the
1609// result can change.
1610TEST_F(ScalarReplacementTest, TestAccessChainWithNoIndexes) {
1611  const std::string text = R"(
1612               OpCapability Shader
1613               OpMemoryModel Logical GLSL450
1614               OpEntryPoint Fragment %1 "main"
1615               OpExecutionMode %1 OriginLowerLeft
1616       %void = OpTypeVoid
1617          %3 = OpTypeFunction %void
1618      %float = OpTypeFloat 32
1619  %_struct_5 = OpTypeStruct %float
1620%_ptr_Function__struct_5 = OpTypePointer Function %_struct_5
1621          %1 = OpFunction %void None %3
1622          %7 = OpLabel
1623          %8 = OpVariable %_ptr_Function__struct_5 Function
1624          %9 = OpAccessChain %_ptr_Function__struct_5 %8
1625               OpReturn
1626               OpFunctionEnd
1627  )";
1628
1629  auto result =
1630      SinglePassRunAndDisassemble<ScalarReplacementPass>(text, true, false);
1631  EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
1632}
1633
1634// Test that id overflow is handled gracefully.
1635TEST_F(ScalarReplacementTest, IdBoundOverflow1) {
1636  const std::string text = R"(
1637OpCapability ImageQuery
1638OpMemoryModel Logical GLSL450
1639OpEntryPoint Fragment %4 "main"
1640OpExecutionMode %4 OriginUpperLeft
1641OpDecorate %4194302 DescriptorSet 1073495039
1642%2 = OpTypeVoid
1643%3 = OpTypeFunction %2
1644%6 = OpTypeFloat 32
1645%7 = OpTypeStruct %6 %6
1646%557056 = OpTypeStruct %7
1647%9 = OpTypePointer Function %7
1648%18 = OpTypeFunction %7 %9
1649%4 = OpFunction %2 Pure|Const %3
1650%1836763 = OpLabel
1651%4194302 = OpVariable %9 Function
1652%10 = OpVariable %9 Function
1653OpKill
1654%4194301 = OpLabel
1655%524296 = OpLoad %7 %4194302
1656OpKill
1657OpFunctionEnd
1658  )";
1659
1660  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1661
1662  std::vector<Message> messages = {
1663      {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."},
1664      {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}};
1665  SetMessageConsumer(GetTestMessageConsumer(messages));
1666  auto result = SinglePassRunToBinary<ScalarReplacementPass>(text, true, false);
1667  EXPECT_EQ(Pass::Status::Failure, std::get<1>(result));
1668}
1669
1670// Test that id overflow is handled gracefully.
1671TEST_F(ScalarReplacementTest, IdBoundOverflow2) {
1672  const std::string text = R"(
1673OpCapability Shader
1674OpMemoryModel Logical GLSL450
1675OpEntryPoint Fragment %4 "main" %17
1676OpExecutionMode %4 OriginUpperLeft
1677%2 = OpTypeVoid
1678%3 = OpTypeFunction %2
1679%6 = OpTypeFloat 32
1680%7 = OpTypeVector %6 4
1681%8 = OpTypeStruct %7
1682%9 = OpTypePointer Function %8
1683%16 = OpTypePointer Output %7
1684%21 = OpTypeInt 32 1
1685%22 = OpConstant %21 0
1686%23 = OpTypePointer Function %7
1687%17 = OpVariable %16 Output
1688%4 = OpFunction %2 None %3
1689%5 = OpLabel
1690%4194300 = OpVariable %23 Function
1691%10 = OpVariable %9 Function
1692%4194301 = OpAccessChain %23 %10 %22
1693%4194302 = OpLoad %7 %4194301
1694OpStore %4194300 %4194302
1695%15 = OpLoad %7 %4194300
1696OpStore %17 %15
1697OpReturn
1698OpFunctionEnd
1699  )";
1700
1701  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1702
1703  std::vector<Message> messages = {
1704      {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}};
1705  SetMessageConsumer(GetTestMessageConsumer(messages));
1706  auto result = SinglePassRunToBinary<ScalarReplacementPass>(text, true, false);
1707  EXPECT_EQ(Pass::Status::Failure, std::get<1>(result));
1708}
1709
1710// Test that id overflow is handled gracefully.
1711TEST_F(ScalarReplacementTest, IdBoundOverflow3) {
1712  const std::string text = R"(
1713OpCapability InterpolationFunction
1714OpExtension "z"
1715OpMemoryModel Logical GLSL450
1716OpEntryPoint Fragment %4 "main"
1717OpExecutionMode %4 OriginUpperLeft
1718%2 = OpTypeVoid
1719%3 = OpTypeFunction %2
1720%6 = OpTypeFloat 32
1721%7 = OpTypeStruct %6 %6
1722%9 = OpTypePointer Function %7
1723%18 = OpTypeFunction %7 %9
1724%21 = OpTypeInt 32 0
1725%22 = OpConstant %21 4293000676
1726%4194302 = OpConstantNull %6
1727%4 = OpFunction %2 Inline|Pure %3
1728%786464 = OpLabel
1729%4194298 = OpVariable %9 Function
1730%10 = OpVariable %9 Function
1731%4194299 = OpUDiv %21 %22 %22
1732%4194300 = OpLoad %7 %10
1733%50959 = OpLoad %7 %4194298
1734OpKill
1735OpFunctionEnd
1736%1 = OpFunction %7 None %18
1737%19 = OpFunctionParameter %9
1738%147667 = OpLabel
1739%2044391 = OpUDiv %21 %22 %22
1740%25 = OpLoad %7 %19
1741OpReturnValue %25
1742OpFunctionEnd
1743%4194295 = OpFunction %2 None %3
1744%4194296 = OpLabel
1745OpKill
1746OpFunctionEnd
1747  )";
1748
1749  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1750
1751  std::vector<Message> messages = {
1752      {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."},
1753      {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."},
1754      {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."},
1755      {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."},
1756      {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."},
1757      {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."},
1758      {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."},
1759      {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."},
1760      {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}};
1761  SetMessageConsumer(GetTestMessageConsumer(messages));
1762  auto result = SinglePassRunToBinary<ScalarReplacementPass>(text, true, false);
1763  EXPECT_EQ(Pass::Status::Failure, std::get<1>(result));
1764}
1765
1766// Test that replacements for OpAccessChain do not go out of bounds.
1767// https://github.com/KhronosGroup/SPIRV-Tools/issues/2609.
1768TEST_F(ScalarReplacementTest, OutOfBoundOpAccessChain) {
1769  const std::string text = R"(
1770               OpCapability Shader
1771          %1 = OpExtInstImport "GLSL.std.450"
1772               OpMemoryModel Logical GLSL450
1773               OpEntryPoint Fragment %main "main" %_GLF_color
1774               OpExecutionMode %main OriginUpperLeft
1775               OpSource ESSL 310
1776               OpName %main "main"
1777               OpName %a "a"
1778               OpName %_GLF_color "_GLF_color"
1779               OpDecorate %_GLF_color Location 0
1780       %void = OpTypeVoid
1781          %3 = OpTypeFunction %void
1782        %int = OpTypeInt 32 1
1783%_ptr_Function_int = OpTypePointer Function %int
1784      %int_1 = OpConstant %int 1
1785      %float = OpTypeFloat 32
1786       %uint = OpTypeInt 32 0
1787     %uint_1 = OpConstant %uint 1
1788%_arr_float_uint_1 = OpTypeArray %float %uint_1
1789%_ptr_Function__arr_float_uint_1 = OpTypePointer Function %_arr_float_uint_1
1790%_ptr_Function_float = OpTypePointer Function %float
1791%_ptr_Output_float = OpTypePointer Output %float
1792 %_GLF_color = OpVariable %_ptr_Output_float Output
1793       %main = OpFunction %void None %3
1794          %5 = OpLabel
1795          %a = OpVariable %_ptr_Function__arr_float_uint_1 Function
1796         %21 = OpAccessChain %_ptr_Function_float %a %int_1
1797         %22 = OpLoad %float %21
1798               OpStore %_GLF_color %22
1799               OpReturn
1800               OpFunctionEnd
1801  )";
1802
1803  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1804
1805  auto result =
1806      SinglePassRunAndDisassemble<ScalarReplacementPass>(text, true, false);
1807  EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
1808}
1809
1810TEST_F(ScalarReplacementTest, CharIndex) {
1811  const std::string text = R"(
1812; CHECK: [[int:%\w+]] = OpTypeInt 32 0
1813; CHECK: [[ptr:%\w+]] = OpTypePointer Function [[int]]
1814; CHECK: OpVariable [[ptr]] Function
1815OpCapability Shader
1816OpCapability Int8
1817OpMemoryModel Logical GLSL450
1818OpEntryPoint GLCompute %main "main"
1819OpExecutionMode %main LocalSize 1 1 1
1820%void = OpTypeVoid
1821%int = OpTypeInt 32 0
1822%int_1024 = OpConstant %int 1024
1823%char = OpTypeInt 8 0
1824%char_1 = OpConstant %char 1
1825%array = OpTypeArray %int %int_1024
1826%ptr_func_array = OpTypePointer Function %array
1827%ptr_func_int = OpTypePointer Function %int
1828%void_fn = OpTypeFunction %void
1829%main = OpFunction %void None %void_fn
1830%entry = OpLabel
1831%var = OpVariable %ptr_func_array Function
1832%gep = OpAccessChain %ptr_func_int %var %char_1
1833OpStore %gep %int_1024
1834OpReturn
1835OpFunctionEnd
1836)";
1837
1838  SinglePassRunAndMatch<ScalarReplacementPass>(text, true, 0);
1839}
1840
1841TEST_F(ScalarReplacementTest, OutOfBoundsOpAccessChainNegative) {
1842  const std::string text = R"(
1843OpCapability Shader
1844OpCapability Int8
1845OpMemoryModel Logical GLSL450
1846OpEntryPoint GLCompute %main "main"
1847OpExecutionMode %main LocalSize 1 1 1
1848%void = OpTypeVoid
1849%int = OpTypeInt 32 0
1850%int_1024 = OpConstant %int 1024
1851%char = OpTypeInt 8 1
1852%char_n1 = OpConstant %char -1
1853%array = OpTypeArray %int %int_1024
1854%ptr_func_array = OpTypePointer Function %array
1855%ptr_func_int = OpTypePointer Function %int
1856%void_fn = OpTypeFunction %void
1857%main = OpFunction %void None %void_fn
1858%entry = OpLabel
1859%var = OpVariable %ptr_func_array Function
1860%gep = OpAccessChain %ptr_func_int %var %char_n1
1861OpStore %gep %int_1024
1862OpReturn
1863OpFunctionEnd
1864)";
1865
1866  auto result =
1867      SinglePassRunAndDisassemble<ScalarReplacementPass>(text, true, true, 0);
1868  EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
1869}
1870
1871TEST_F(ScalarReplacementTest, RelaxedPrecisionMemberDecoration) {
1872  const std::string text = R"(
1873; CHECK: OpDecorate {{%\w+}} RelaxedPrecision
1874; CHECK: OpDecorate [[new_var:%\w+]] RelaxedPrecision
1875; CHECK: [[new_var]] = OpVariable %_ptr_Function_v3float Function
1876; CHECK: OpLoad %v3float [[new_var]]
1877               OpCapability Shader
1878               OpMemoryModel Logical GLSL450
1879               OpEntryPoint Vertex %1 "Draw2DTexCol_VS" %2 %3
1880               OpSource HLSL 600
1881               OpDecorate %2 Location 0
1882               OpDecorate %3 Location 1
1883               OpDecorate %3 RelaxedPrecision
1884               OpMemberDecorate %_struct_4 1 RelaxedPrecision
1885      %float = OpTypeFloat 32
1886        %int = OpTypeInt 32 1
1887      %int_1 = OpConstant %int 1
1888    %v3float = OpTypeVector %float 3
1889%_ptr_Input_v3float = OpTypePointer Input %v3float
1890       %void = OpTypeVoid
1891         %11 = OpTypeFunction %void
1892  %_struct_4 = OpTypeStruct %v3float %v3float
1893%_ptr_Function__struct_4 = OpTypePointer Function %_struct_4
1894%_ptr_Function_v3float = OpTypePointer Function %v3float
1895          %2 = OpVariable %_ptr_Input_v3float Input
1896          %3 = OpVariable %_ptr_Input_v3float Input
1897          %1 = OpFunction %void None %11
1898         %14 = OpLabel
1899         %15 = OpVariable %_ptr_Function__struct_4 Function
1900         %16 = OpLoad %v3float %2
1901         %17 = OpLoad %v3float %3
1902         %18 = OpCompositeConstruct %_struct_4 %16 %17
1903               OpStore %15 %18
1904         %19 = OpAccessChain %_ptr_Function_v3float %15 %int_1
1905         %20 = OpLoad %v3float %19
1906               OpReturn
1907               OpFunctionEnd
1908)";
1909
1910  SinglePassRunAndMatch<ScalarReplacementPass>(text, true);
1911}
1912
1913TEST_F(ScalarReplacementTest, DebugDeclare) {
1914  const std::string text = R"(
1915OpCapability Shader
1916OpCapability Linkage
1917%ext = OpExtInstImport "OpenCL.DebugInfo.100"
1918OpMemoryModel Logical GLSL450
1919%test = OpString "test"
1920OpName %6 "simple_struct"
1921%1 = OpTypeVoid
1922%2 = OpTypeInt 32 0
1923%uint_32 = OpConstant %2 32
1924%3 = OpTypeStruct %2 %2 %2 %2
1925%4 = OpTypePointer Function %3
1926%5 = OpTypePointer Function %2
1927%6 = OpTypeFunction %2
1928%7 = OpConstantNull %3
1929%8 = OpConstant %2 0
1930%9 = OpConstant %2 1
1931%10 = OpConstant %2 2
1932%11 = OpConstant %2 3
1933%null_expr = OpExtInst %1 %ext DebugExpression
1934%src = OpExtInst %1 %ext DebugSource %test
1935%cu = OpExtInst %1 %ext DebugCompilationUnit 1 4 %src HLSL
1936%dbg_tf = OpExtInst %1 %ext DebugTypeBasic %test %uint_32 Float
1937%main_ty = OpExtInst %1 %ext DebugTypeFunction FlagIsProtected|FlagIsPrivate %1
1938%dbg_main = OpExtInst %1 %ext DebugFunction %test %main_ty %src 0 0 %cu %test FlagIsProtected|FlagIsPrivate 0 %12
1939%dbg_foo = OpExtInst %1 %ext DebugLocalVariable %test %dbg_tf %src 0 0 %dbg_main FlagIsLocal
1940%12 = OpFunction %2 None %6
1941%13 = OpLabel
1942%scope = OpExtInst %1 %ext DebugScope %dbg_main
1943%14 = OpVariable %4 Function %7
1944
1945; CHECK: [[deref:%\w+]] = OpExtInst %void [[ext:%\w+]] DebugOperation Deref
1946; CHECK: [[dbg_local_var:%\w+]] = OpExtInst %void [[ext]] DebugLocalVariable
1947; CHECK: [[deref_expr:%\w+]] = OpExtInst %void [[ext]] DebugExpression [[deref]]
1948; CHECK: [[repl3:%\w+]] = OpVariable %_ptr_Function_uint Function
1949; CHECK: [[repl2:%\w+]] = OpVariable %_ptr_Function_uint Function
1950; CHECK: [[repl1:%\w+]] = OpVariable %_ptr_Function_uint Function
1951; CHECK: [[repl0:%\w+]] = OpVariable %_ptr_Function_uint Function
1952; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl3]] [[deref_expr]] %int_3
1953; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl2]] [[deref_expr]] %int_2
1954; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl1]] [[deref_expr]] %int_1
1955; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl0]] [[deref_expr]] %int_0
1956; CHECK-NOT: DebugDeclare
1957%decl = OpExtInst %1 %ext DebugDeclare %dbg_foo %14 %null_expr
1958
1959%15 = OpInBoundsAccessChain %5 %14 %8
1960%16 = OpLoad %2 %15
1961%17 = OpAccessChain %5 %14 %10
1962%18 = OpLoad %2 %17
1963%19 = OpIAdd %2 %16 %18
1964OpReturnValue %19
1965OpFunctionEnd
1966)";
1967
1968  SinglePassRunAndMatch<ScalarReplacementPass>(text, true);
1969}
1970
1971TEST_F(ScalarReplacementTest, DebugValue) {
1972  const std::string text = R"(
1973OpCapability Shader
1974OpCapability Linkage
1975%ext = OpExtInstImport "OpenCL.DebugInfo.100"
1976OpMemoryModel Logical GLSL450
1977%test = OpString "test"
1978OpName %6 "simple_struct"
1979%1 = OpTypeVoid
1980%2 = OpTypeInt 32 0
1981%uint_32 = OpConstant %2 32
1982%3 = OpTypeStruct %2 %2 %2 %2
1983%4 = OpTypePointer Function %3
1984%5 = OpTypePointer Function %2
1985%6 = OpTypeFunction %2
1986%7 = OpConstantNull %3
1987%8 = OpConstant %2 0
1988%9 = OpConstant %2 1
1989%10 = OpConstant %2 2
1990%11 = OpConstant %2 3
1991%deref = OpExtInst %1 %ext DebugOperation Deref
1992%deref_expr = OpExtInst %1 %ext DebugExpression %deref
1993%null_expr = OpExtInst %1 %ext DebugExpression
1994%src = OpExtInst %1 %ext DebugSource %test
1995%cu = OpExtInst %1 %ext DebugCompilationUnit 1 4 %src HLSL
1996%dbg_tf = OpExtInst %1 %ext DebugTypeBasic %test %uint_32 Float
1997%main_ty = OpExtInst %1 %ext DebugTypeFunction FlagIsProtected|FlagIsPrivate %1
1998%dbg_main = OpExtInst %1 %ext DebugFunction %test %main_ty %src 0 0 %cu %test FlagIsProtected|FlagIsPrivate 0 %12
1999%dbg_foo = OpExtInst %1 %ext DebugLocalVariable %test %dbg_tf %src 0 0 %dbg_main FlagIsLocal
2000%12 = OpFunction %2 None %6
2001%13 = OpLabel
2002%scope = OpExtInst %1 %ext DebugScope %dbg_main
2003%14 = OpVariable %4 Function %7
2004
2005; CHECK: [[deref:%\w+]] = OpExtInst %void [[ext:%\w+]] DebugOperation Deref
2006; CHECK: [[deref_expr:%\w+]] = OpExtInst %void [[ext]] DebugExpression [[deref]]
2007; CHECK: [[dbg_local_var:%\w+]] = OpExtInst %void [[ext]] DebugLocalVariable
2008; CHECK: [[repl3:%\w+]] = OpVariable %_ptr_Function_uint Function
2009; CHECK: [[repl2:%\w+]] = OpVariable %_ptr_Function_uint Function
2010; CHECK: [[repl1:%\w+]] = OpVariable %_ptr_Function_uint Function
2011; CHECK: [[repl0:%\w+]] = OpVariable %_ptr_Function_uint Function
2012; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl0]] [[deref_expr]] %int_0
2013; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl1]] [[deref_expr]] %int_1
2014; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl2]] [[deref_expr]] %int_2
2015; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl3]] [[deref_expr]] %int_3
2016%value = OpExtInst %1 %ext DebugValue %dbg_foo %14 %deref_expr
2017
2018%15 = OpInBoundsAccessChain %5 %14 %8
2019%16 = OpLoad %2 %15
2020%17 = OpAccessChain %5 %14 %10
2021%18 = OpLoad %2 %17
2022%19 = OpIAdd %2 %16 %18
2023OpReturnValue %19
2024OpFunctionEnd
2025)";
2026
2027  SinglePassRunAndMatch<ScalarReplacementPass>(text, true);
2028}
2029
2030TEST_F(ScalarReplacementTest, DebugDeclareRecursive) {
2031  const std::string text = R"(
2032OpCapability Shader
2033OpCapability Linkage
2034%ext = OpExtInstImport "OpenCL.DebugInfo.100"
2035OpMemoryModel Logical GLSL450
2036%test = OpString "test"
2037OpName %6 "simple_struct"
2038%1 = OpTypeVoid
2039%2 = OpTypeInt 32 0
2040%uint_32 = OpConstant %2 32
2041%float = OpTypeFloat 32
2042%float_1 = OpConstant %float 1
2043%member = OpTypeStruct %2 %float
2044%3 = OpTypeStruct %2 %member %float
2045%4 = OpTypePointer Function %3
2046%5 = OpTypePointer Function %2
2047%ptr_float_Function = OpTypePointer Function %float
2048%6 = OpTypeFunction %2
2049%cmember = OpConstantComposite %member %uint_32 %float_1
2050%7 = OpConstantComposite %3 %uint_32 %cmember %float_1
2051%8 = OpConstant %2 0
2052%9 = OpConstant %2 1
2053%10 = OpConstant %2 2
2054%null_expr = OpExtInst %1 %ext DebugExpression
2055%src = OpExtInst %1 %ext DebugSource %test
2056%cu = OpExtInst %1 %ext DebugCompilationUnit 1 4 %src HLSL
2057%dbg_tf = OpExtInst %1 %ext DebugTypeBasic %test %uint_32 Float
2058%main_ty = OpExtInst %1 %ext DebugTypeFunction FlagIsProtected|FlagIsPrivate %1
2059%dbg_main = OpExtInst %1 %ext DebugFunction %test %main_ty %src 0 0 %cu %test FlagIsProtected|FlagIsPrivate 0 %12
2060%dbg_foo = OpExtInst %1 %ext DebugLocalVariable %test %dbg_tf %src 0 0 %dbg_main FlagIsLocal
2061%12 = OpFunction %2 None %6
2062%13 = OpLabel
2063%scope = OpExtInst %1 %ext DebugScope %dbg_main
2064%14 = OpVariable %4 Function %7
2065
2066; CHECK: [[deref:%\w+]] = OpExtInst %void [[ext:%\w+]] DebugOperation Deref
2067; CHECK: [[dbg_local_var:%\w+]] = OpExtInst %void [[ext]] DebugLocalVariable
2068; CHECK: [[deref_expr:%\w+]] = OpExtInst %void [[ext]] DebugExpression [[deref]]
2069; CHECK: [[repl2:%\w+]] = OpVariable %_ptr_Function_float Function %float_1
2070; CHECK: [[repl1:%\w+]] = OpVariable %_ptr_Function_uint Function %uint_32
2071; CHECK: [[repl3:%\w+]] = OpVariable %_ptr_Function_float Function %float_1
2072; CHECK: [[repl0:%\w+]] = OpVariable %_ptr_Function_uint Function %uint_32
2073; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl3]] [[deref_expr]] %int_2
2074; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl1]] [[deref_expr]] %int_1 %int_0
2075; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl2]] [[deref_expr]] %int_1 %int_1
2076; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl0]] [[deref_expr]] %int_0
2077; CHECK-NOT: DebugDeclare
2078%decl = OpExtInst %1 %ext DebugDeclare %dbg_foo %14 %null_expr
2079
2080%15 = OpInBoundsAccessChain %5 %14 %8
2081%16 = OpLoad %2 %15
2082%17 = OpAccessChain %ptr_float_Function %14 %10
2083%18 = OpLoad %float %17
2084%value = OpConvertFToU %2 %18
2085%19 = OpIAdd %2 %16 %value
2086OpReturnValue %19
2087OpFunctionEnd
2088)";
2089
2090  SinglePassRunAndMatch<ScalarReplacementPass>(text, true);
2091}
2092
2093TEST_F(ScalarReplacementTest, DebugValueWithIndex) {
2094  const std::string text = R"(
2095OpCapability Shader
2096OpCapability Linkage
2097%ext = OpExtInstImport "OpenCL.DebugInfo.100"
2098OpMemoryModel Logical GLSL450
2099%test = OpString "test"
2100OpName %6 "simple_struct"
2101%1 = OpTypeVoid
2102%2 = OpTypeInt 32 0
2103%uint_32 = OpConstant %2 32
2104%3 = OpTypeStruct %2 %2 %2 %2
2105%4 = OpTypePointer Function %3
2106%5 = OpTypePointer Function %2
2107%6 = OpTypeFunction %2
2108%7 = OpConstantNull %3
2109%8 = OpConstant %2 0
2110%9 = OpConstant %2 1
2111%10 = OpConstant %2 2
2112%11 = OpConstant %2 3
2113%deref = OpExtInst %1 %ext DebugOperation Deref
2114%deref_expr = OpExtInst %1 %ext DebugExpression %deref
2115%null_expr = OpExtInst %1 %ext DebugExpression
2116%src = OpExtInst %1 %ext DebugSource %test
2117%cu = OpExtInst %1 %ext DebugCompilationUnit 1 4 %src HLSL
2118%dbg_tf = OpExtInst %1 %ext DebugTypeBasic %test %uint_32 Float
2119%main_ty = OpExtInst %1 %ext DebugTypeFunction FlagIsProtected|FlagIsPrivate %1
2120%dbg_main = OpExtInst %1 %ext DebugFunction %test %main_ty %src 0 0 %cu %test FlagIsProtected|FlagIsPrivate 0 %12
2121%dbg_foo = OpExtInst %1 %ext DebugLocalVariable %test %dbg_tf %src 0 0 %dbg_main FlagIsLocal
2122%12 = OpFunction %2 None %6
2123%13 = OpLabel
2124%scope = OpExtInst %1 %ext DebugScope %dbg_main
2125%14 = OpVariable %4 Function %7
2126
2127; CHECK: [[deref:%\w+]] = OpExtInst %void [[ext:%\w+]] DebugOperation Deref
2128; CHECK: [[deref_expr:%\w+]] = OpExtInst %void [[ext]] DebugExpression [[deref]]
2129; CHECK: [[dbg_local_var:%\w+]] = OpExtInst %void [[ext]] DebugLocalVariable
2130; CHECK: [[repl3:%\w+]] = OpVariable %_ptr_Function_uint Function
2131; CHECK: [[repl2:%\w+]] = OpVariable %_ptr_Function_uint Function
2132; CHECK: [[repl1:%\w+]] = OpVariable %_ptr_Function_uint Function
2133; CHECK: [[repl0:%\w+]] = OpVariable %_ptr_Function_uint Function
2134; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl0]] [[deref_expr]] %uint_0 %uint_1 %uint_2 %int_0
2135; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl1]] [[deref_expr]] %uint_0 %uint_1 %uint_2 %int_1
2136; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl2]] [[deref_expr]] %uint_0 %uint_1 %uint_2 %int_2
2137; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl3]] [[deref_expr]] %uint_0 %uint_1 %uint_2 %int_3
2138%value = OpExtInst %1 %ext DebugValue %dbg_foo %14 %deref_expr %8 %9 %10
2139
2140%15 = OpInBoundsAccessChain %5 %14 %8
2141%16 = OpLoad %2 %15
2142%17 = OpAccessChain %5 %14 %10
2143%18 = OpLoad %2 %17
2144%19 = OpIAdd %2 %16 %18
2145OpReturnValue %19
2146OpFunctionEnd
2147)";
2148
2149  SinglePassRunAndMatch<ScalarReplacementPass>(text, true);
2150}
2151
2152TEST_F(ScalarReplacementTest, DebugDeclareForVariableInOtherBB) {
2153  const std::string text = R"(
2154OpCapability Shader
2155OpCapability Linkage
2156%ext = OpExtInstImport "OpenCL.DebugInfo.100"
2157OpMemoryModel Logical GLSL450
2158%test = OpString "test"
2159OpName %6 "simple_struct"
2160%1 = OpTypeVoid
2161%2 = OpTypeInt 32 0
2162%uint_32 = OpConstant %2 32
2163%3 = OpTypeStruct %2 %2 %2 %2
2164%4 = OpTypePointer Function %3
2165%5 = OpTypePointer Function %2
2166%6 = OpTypeFunction %2
2167%7 = OpConstantNull %3
2168%8 = OpConstant %2 0
2169%9 = OpConstant %2 1
2170%10 = OpConstant %2 2
2171%11 = OpConstant %2 3
2172%deref = OpExtInst %1 %ext DebugOperation Deref
2173%deref_expr = OpExtInst %1 %ext DebugExpression %deref
2174%null_expr = OpExtInst %1 %ext DebugExpression
2175%src = OpExtInst %1 %ext DebugSource %test
2176%cu = OpExtInst %1 %ext DebugCompilationUnit 1 4 %src HLSL
2177%dbg_tf = OpExtInst %1 %ext DebugTypeBasic %test %uint_32 Float
2178%main_ty = OpExtInst %1 %ext DebugTypeFunction FlagIsProtected|FlagIsPrivate %1
2179%dbg_main = OpExtInst %1 %ext DebugFunction %test %main_ty %src 0 0 %cu %test FlagIsProtected|FlagIsPrivate 0 %12
2180%dbg_foo = OpExtInst %1 %ext DebugLocalVariable %test %dbg_tf %src 0 0 %dbg_main FlagIsLocal
2181%12 = OpFunction %2 None %6
2182%13 = OpLabel
2183%scope = OpExtInst %1 %ext DebugScope %dbg_main
2184%14 = OpVariable %4 Function %7
2185
2186; CHECK: [[dbg_local_var:%\w+]] = OpExtInst %void [[ext:%\w+]] DebugLocalVariable
2187; CHECK: [[repl3:%\w+]] = OpVariable %_ptr_Function_uint Function
2188; CHECK: [[repl2:%\w+]] = OpVariable %_ptr_Function_uint Function
2189; CHECK: [[repl1:%\w+]] = OpVariable %_ptr_Function_uint Function
2190; CHECK: [[repl0:%\w+]] = OpVariable %_ptr_Function_uint Function
2191; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl3]] [[deref_expr:%\w+]] %int_3
2192; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl2]] [[deref_expr]] %int_2
2193; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl1]] [[deref_expr]] %int_1
2194; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl0]] [[deref_expr]] %int_0
2195
2196OpBranch %20
2197%20 = OpLabel
2198%value = OpExtInst %1 %ext DebugDeclare %dbg_foo %14 %null_expr
2199%15 = OpInBoundsAccessChain %5 %14 %8
2200%16 = OpLoad %2 %15
2201%17 = OpAccessChain %5 %14 %10
2202%18 = OpLoad %2 %17
2203%19 = OpIAdd %2 %16 %18
2204OpReturnValue %19
2205OpFunctionEnd
2206)";
2207
2208  SinglePassRunAndMatch<ScalarReplacementPass>(text, true);
2209}
2210
2211TEST_F(ScalarReplacementTest, ImageTexelPointer) {
2212  // Test whether the scalar replacement correctly checks the
2213  // OpImageTexelPointer user of an aggregate with an image type.
2214  const std::string text = R"(
2215;
2216; CHECK: [[imgTy:%\w+]] = OpTypeImage %uint Buffer 2 0 0 2 R32ui
2217; CHECK: [[ptrImgTy:%\w+]] = OpTypePointer Function [[imgTy]]
2218; CHECK: [[img:%\w+]] = OpVariable [[ptrImgTy]] Function
2219; CHECK: [[imgTexelPtr:%\w+]] = OpImageTexelPointer {{%\w+}} [[img]] %uint_0 %uint_0
2220; CHECK: OpAtomicIAdd %uint [[imgTexelPtr]] %uint_1 %uint_0 %uint_1
2221;
2222OpCapability Shader
2223OpCapability SampledBuffer
2224OpCapability ImageBuffer
2225OpMemoryModel Logical GLSL450
2226OpEntryPoint GLCompute %1 "main"
2227OpExecutionMode %1 LocalSize 64 1 1
2228%void = OpTypeVoid
2229%uint = OpTypeInt 32 0
2230%uint_0 = OpConstant %uint 0
2231%uint_1 = OpConstant %uint 1
2232%_ptr_Image_uint = OpTypePointer Image %uint
2233%type_buffer_image = OpTypeImage %uint Buffer 2 0 0 2 R32ui
2234%_ptr_Function_type_buffer_image = OpTypePointer Function %type_buffer_image
2235%image_struct = OpTypeStruct %type_buffer_image %type_buffer_image
2236%_ptr_Function_image_struct = OpTypePointer Function %image_struct
2237%func = OpTypeFunction %void
2238%1 = OpFunction %void None %func
2239%2 = OpLabel
2240%3 = OpVariable %_ptr_Function_image_struct Function
2241%4 = OpAccessChain %_ptr_Function_type_buffer_image %3 %uint_1
2242%5 = OpImageTexelPointer %_ptr_Image_uint %4 %uint_0 %uint_0
2243%6 = OpAtomicIAdd %uint %5 %uint_1 %uint_0 %uint_1
2244OpReturn
2245OpFunctionEnd
2246  )";
2247
2248  SinglePassRunAndMatch<ScalarReplacementPass>(text, false);
2249}
2250
2251TEST_F(ScalarReplacementTest, FunctionDeclaration) {
2252  // Make sure the pass works with a function declaration that is called.
2253  const std::string text = R"(OpCapability Addresses
2254OpCapability Linkage
2255OpCapability Kernel
2256OpCapability Int8
2257%1 = OpExtInstImport "OpenCL.std"
2258OpMemoryModel Physical64 OpenCL
2259OpEntryPoint Kernel %2 "_Z23julia__1166_kernel_77094Bool"
2260OpExecutionMode %2 ContractionOff
2261OpSource Unknown 0
2262OpDecorate %3 LinkageAttributes "julia_error_7712" Import
2263%void = OpTypeVoid
2264%5 = OpTypeFunction %void
2265%3 = OpFunction %void None %5
2266OpFunctionEnd
2267%2 = OpFunction %void None %5
2268%6 = OpLabel
2269%7 = OpFunctionCall %void %3
2270OpReturn
2271OpFunctionEnd
2272)";
2273
2274  SinglePassRunAndCheck<ScalarReplacementPass>(text, text, false);
2275}
2276
2277TEST_F(ScalarReplacementTest, UndefImageMember) {
2278  // Test that scalar replacement creates an undef for a type that cannot have
2279  // and OpConstantNull.
2280  const std::string text = R"(
2281; CHECK: [[image_type:%\w+]] = OpTypeSampledImage {{%\w+}}
2282; CHECK: [[struct_type:%\w+]] = OpTypeStruct [[image_type]]
2283; CHECK: [[undef:%\w+]] = OpUndef [[image_type]]
2284; CHECK: {{%\w+}} = OpCompositeConstruct [[struct_type]] [[undef]]
2285               OpCapability Shader
2286          %1 = OpExtInstImport "GLSL.std.450"
2287               OpMemoryModel Logical GLSL450
2288               OpEntryPoint Fragment %2 "main"
2289               OpExecutionMode %2 OriginUpperLeft
2290       %void = OpTypeVoid
2291          %4 = OpTypeFunction %void
2292      %float = OpTypeFloat 32
2293          %6 = OpTypeImage %float 2D 0 0 0 1 Unknown
2294          %7 = OpTypeSampledImage %6
2295  %_struct_8 = OpTypeStruct %7
2296          %9 = OpTypeFunction %_struct_8
2297         %10 = OpUndef %_struct_8
2298%_ptr_Function__struct_8 = OpTypePointer Function %_struct_8
2299          %2 = OpFunction %void None %4
2300         %11 = OpLabel
2301         %16 = OpVariable %_ptr_Function__struct_8 Function
2302               OpStore %16 %10
2303         %12 = OpLoad %_struct_8 %16
2304               OpReturn
2305               OpFunctionEnd
2306  )";
2307
2308  SinglePassRunAndMatch<ScalarReplacementPass>(text, true);
2309}
2310
2311TEST_F(ScalarReplacementTest, RestrictPointer) {
2312  // This test makes sure that a variable with the restrict pointer decoration
2313  // is replaced, and that the pointer is applied to the new variable.
2314  const std::string text = R"(
2315; CHECK: OpDecorate [[new_var:%\w+]] RestrictPointer
2316; CHECK: [[struct_type:%\w+]] = OpTypeStruct %int
2317; CHECK: [[ptr_type:%\w+]] = OpTypePointer PhysicalStorageBuffer [[struct_type]]
2318; CHECK: [[dup_struct_type:%\w+]] = OpTypeStruct %int
2319; CHECK: {{%\w+}} = OpTypePointer PhysicalStorageBuffer [[dup_struct_type]]
2320; CHECK: [[var_type:%\w+]] = OpTypePointer Function [[ptr_type]]
2321; CHECK: [[new_var]] = OpVariable [[var_type]] Function
2322               OpCapability Shader
2323               OpCapability PhysicalStorageBufferAddresses
2324          %1 = OpExtInstImport "GLSL.std.450"
2325               OpMemoryModel PhysicalStorageBuffer64 GLSL450
2326               OpEntryPoint Fragment %2 "main"
2327               OpExecutionMode %2 OriginUpperLeft
2328               OpMemberDecorate %3 0 Offset 0
2329               OpDecorate %3 Block
2330               OpMemberDecorate %4 0 Offset 0
2331               OpDecorate %4 Block
2332               OpDecorate %5 RestrictPointer
2333          %6 = OpTypeVoid
2334          %7 = OpTypeFunction %6
2335          %8 = OpTypeInt 32 1
2336          %9 = OpConstant %8 0
2337          %3 = OpTypeStruct %8
2338         %10 = OpTypePointer PhysicalStorageBuffer %3
2339         %11 = OpTypeStruct %10
2340          %4 = OpTypeStruct %8
2341         %12 = OpTypePointer PhysicalStorageBuffer %4
2342         %13 = OpTypePointer Function %11
2343         %14 = OpTypePointer Function %10
2344         %15 = OpTypePointer Function %12
2345         %16 = OpUndef %11
2346          %2 = OpFunction %6 None %7
2347         %17 = OpLabel
2348          %5 = OpVariable %13 Function
2349               OpStore %5 %16
2350         %18 = OpAccessChain %14 %5 %9
2351               OpReturn
2352               OpFunctionEnd
2353  )";
2354
2355  SetTargetEnv(SPV_ENV_UNIVERSAL_1_6);
2356  SinglePassRunAndMatch<ScalarReplacementPass>(text, true);
2357}
2358
2359}  // namespace
2360}  // namespace opt
2361}  // namespace spvtools
2362