1 // Copyright (c) 2017 Valve Corporation
2 // Copyright (c) 2017 LunarG Inc.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 
16 #include <string>
17 #include <vector>
18 
19 #include "test/opt/pass_fixture.h"
20 #include "test/opt/pass_utils.h"
21 
22 namespace spvtools {
23 namespace opt {
24 namespace {
25 
26 // Returns the initial part of the assembly text for a valid
27 // SPIR-V module, including instructions prior to decorations.
PreambleAssembly()28 std::string PreambleAssembly() {
29   return
30       R"(OpCapability Shader
31 OpMemoryModel Logical GLSL450
32 OpEntryPoint Fragment %main "main" %hue %saturation %value
33 OpExecutionMode %main OriginUpperLeft
34 OpName %main "main"
35 OpName %void_fn "void_fn"
36 OpName %hue "hue"
37 OpName %saturation "saturation"
38 OpName %value "value"
39 OpName %entry "entry"
40 OpName %Point "Point"
41 OpName %Camera "Camera"
42 )";
43 }
44 
45 // Returns types
TypesAndFunctionsAssembly()46 std::string TypesAndFunctionsAssembly() {
47   return
48       R"(%void = OpTypeVoid
49 %void_fn = OpTypeFunction %void
50 %float = OpTypeFloat 32
51 %Point = OpTypeStruct %float %float %float
52 %Camera = OpTypeStruct %float %float
53 %_ptr_Input_float = OpTypePointer Input %float
54 %hue = OpVariable %_ptr_Input_float Input
55 %saturation = OpVariable %_ptr_Input_float Input
56 %value = OpVariable %_ptr_Input_float Input
57 %main = OpFunction %void None %void_fn
58 %entry = OpLabel
59 OpReturn
60 OpFunctionEnd
61 )";
62 }
63 
64 struct FlattenDecorationCase {
65   // Names and decorations before the pass.
66   std::string input;
67   // Names and decorations after the pass.
68   std::string expected;
69 };
70 
71 using FlattenDecorationTest =
72     PassTest<::testing::TestWithParam<FlattenDecorationCase>>;
73 
TEST_P(FlattenDecorationTest, TransformsDecorations)74 TEST_P(FlattenDecorationTest, TransformsDecorations) {
75   const auto before =
76       PreambleAssembly() + GetParam().input + TypesAndFunctionsAssembly();
77   const auto after =
78       PreambleAssembly() + GetParam().expected + TypesAndFunctionsAssembly();
79 
80   SinglePassRunAndCheck<FlattenDecorationPass>(before, after, false, true);
81 }
82 
83 INSTANTIATE_TEST_SUITE_P(NoUses, FlattenDecorationTest,
84                          ::testing::ValuesIn(std::vector<FlattenDecorationCase>{
85                              // No OpDecorationGroup
86                              {"", ""},
87 
88                              // OpDecorationGroup without any uses, and
89                              // no OpName.
90                              {"%group = OpDecorationGroup\n", ""},
91 
92                              // OpDecorationGroup without any uses, and
93                              // with OpName targeting it. Proves you must
94                              // remove the names as well.
95                              {"OpName %group \"group\"\n"
96                               "%group = OpDecorationGroup\n",
97                               ""},
98 
99                              // OpDecorationGroup with decorations that
100                              // target it, but no uses in OpGroupDecorate
101                              // or OpGroupMemberDecorate instructions.
102                              {"OpDecorate %group Flat\n"
103                               "OpDecorate %group NoPerspective\n"
104                               "%group = OpDecorationGroup\n",
105                               ""},
106                          }));
107 
108 INSTANTIATE_TEST_SUITE_P(OpGroupDecorate, FlattenDecorationTest,
109                          ::testing::ValuesIn(std::vector<FlattenDecorationCase>{
110                              // One OpGroupDecorate
111                              {"OpName %group \"group\"\n"
112                               "OpDecorate %group Flat\n"
113                               "OpDecorate %group NoPerspective\n"
114                               "%group = OpDecorationGroup\n"
115                               "OpGroupDecorate %group %hue %saturation\n",
116                               "OpDecorate %hue Flat\n"
117                               "OpDecorate %saturation Flat\n"
118                               "OpDecorate %hue NoPerspective\n"
119                               "OpDecorate %saturation NoPerspective\n"},
120                              // Multiple OpGroupDecorate
121                              {"OpName %group \"group\"\n"
122                               "OpDecorate %group Flat\n"
123                               "OpDecorate %group NoPerspective\n"
124                               "%group = OpDecorationGroup\n"
125                               "OpGroupDecorate %group %hue %value\n"
126                               "OpGroupDecorate %group %saturation\n",
127                               "OpDecorate %hue Flat\n"
128                               "OpDecorate %value Flat\n"
129                               "OpDecorate %saturation Flat\n"
130                               "OpDecorate %hue NoPerspective\n"
131                               "OpDecorate %value NoPerspective\n"
132                               "OpDecorate %saturation NoPerspective\n"},
133                              // Two group decorations, interleaved
134                              {"OpName %group0 \"group0\"\n"
135                               "OpName %group1 \"group1\"\n"
136                               "OpDecorate %group0 Flat\n"
137                               "OpDecorate %group1 NoPerspective\n"
138                               "%group0 = OpDecorationGroup\n"
139                               "%group1 = OpDecorationGroup\n"
140                               "OpGroupDecorate %group0 %hue %value\n"
141                               "OpGroupDecorate %group1 %saturation\n",
142                               "OpDecorate %hue Flat\n"
143                               "OpDecorate %value Flat\n"
144                               "OpDecorate %saturation NoPerspective\n"},
145                              // Decoration with operands
146                              {"OpName %group \"group\"\n"
147                               "OpDecorate %group Location 42\n"
148                               "%group = OpDecorationGroup\n"
149                               "OpGroupDecorate %group %hue %saturation\n",
150                               "OpDecorate %hue Location 42\n"
151                               "OpDecorate %saturation Location 42\n"},
152                          }));
153 
154 INSTANTIATE_TEST_SUITE_P(OpGroupMemberDecorate, FlattenDecorationTest,
155                          ::testing::ValuesIn(std::vector<FlattenDecorationCase>{
156                              // One OpGroupMemberDecorate
157                              {"OpName %group \"group\"\n"
158                               "OpDecorate %group Flat\n"
159                               "OpDecorate %group Offset 16\n"
160                               "%group = OpDecorationGroup\n"
161                               "OpGroupMemberDecorate %group %Point 1\n",
162                               "OpMemberDecorate %Point 1 Flat\n"
163                               "OpMemberDecorate %Point 1 Offset 16\n"},
164                              // Multiple OpGroupMemberDecorate using the same
165                              // decoration group.
166                              {"OpName %group \"group\"\n"
167                               "OpDecorate %group Flat\n"
168                               "OpDecorate %group NoPerspective\n"
169                               "OpDecorate %group Offset 8\n"
170                               "%group = OpDecorationGroup\n"
171                               "OpGroupMemberDecorate %group %Point 2\n"
172                               "OpGroupMemberDecorate %group %Camera 1\n",
173                               "OpMemberDecorate %Point 2 Flat\n"
174                               "OpMemberDecorate %Camera 1 Flat\n"
175                               "OpMemberDecorate %Point 2 NoPerspective\n"
176                               "OpMemberDecorate %Camera 1 NoPerspective\n"
177                               "OpMemberDecorate %Point 2 Offset 8\n"
178                               "OpMemberDecorate %Camera 1 Offset 8\n"},
179                              // Two groups of member decorations, interleaved.
180                              // Decoration is with and without operands.
181                              {"OpName %group0 \"group0\"\n"
182                               "OpName %group1 \"group1\"\n"
183                               "OpDecorate %group0 Flat\n"
184                               "OpDecorate %group0 Offset 8\n"
185                               "OpDecorate %group1 NoPerspective\n"
186                               "OpDecorate %group1 Offset 16\n"
187                               "%group0 = OpDecorationGroup\n"
188                               "%group1 = OpDecorationGroup\n"
189                               "OpGroupMemberDecorate %group0 %Point 0\n"
190                               "OpGroupMemberDecorate %group1 %Point 2\n",
191                               "OpMemberDecorate %Point 0 Flat\n"
192                               "OpMemberDecorate %Point 0 Offset 8\n"
193                               "OpMemberDecorate %Point 2 NoPerspective\n"
194                               "OpMemberDecorate %Point 2 Offset 16\n"},
195                          }));
196 
197 INSTANTIATE_TEST_SUITE_P(UnrelatedDecorations, FlattenDecorationTest,
198                          ::testing::ValuesIn(std::vector<FlattenDecorationCase>{
199                              // A non-group non-member decoration is untouched.
200                              {"OpDecorate %hue Centroid\n"
201                               "OpDecorate %saturation Flat\n",
202                               "OpDecorate %hue Centroid\n"
203                               "OpDecorate %saturation Flat\n"},
204                              // A non-group member decoration is untouched.
205                              {"OpMemberDecorate %Point 0 Offset 0\n"
206                               "OpMemberDecorate %Point 1 Offset 4\n"
207                               "OpMemberDecorate %Point 1 Flat\n",
208                               "OpMemberDecorate %Point 0 Offset 0\n"
209                               "OpMemberDecorate %Point 1 Offset 4\n"
210                               "OpMemberDecorate %Point 1 Flat\n"},
211                              // A non-group non-member decoration survives any
212                              // replacement of group decorations.
213                              {"OpName %group \"group\"\n"
214                               "OpDecorate %group Flat\n"
215                               "OpDecorate %hue Centroid\n"
216                               "OpDecorate %group NoPerspective\n"
217                               "%group = OpDecorationGroup\n"
218                               "OpGroupDecorate %group %hue %saturation\n",
219                               "OpDecorate %hue Flat\n"
220                               "OpDecorate %saturation Flat\n"
221                               "OpDecorate %hue Centroid\n"
222                               "OpDecorate %hue NoPerspective\n"
223                               "OpDecorate %saturation NoPerspective\n"},
224                              // A non-group member decoration survives any
225                              // replacement of group decorations.
226                              {"OpDecorate %group Offset 0\n"
227                               "OpDecorate %group Flat\n"
228                               "OpMemberDecorate %Point 1 Offset 4\n"
229                               "%group = OpDecorationGroup\n"
230                               "OpGroupMemberDecorate %group %Point 0\n",
231                               "OpMemberDecorate %Point 0 Offset 0\n"
232                               "OpMemberDecorate %Point 0 Flat\n"
233                               "OpMemberDecorate %Point 1 Offset 4\n"},
234                          }));
235 
236 }  // namespace
237 }  // namespace opt
238 }  // namespace spvtools
239