1 // Copyright (c) 2022 Google LLC.
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 "source/diff/diff.h"
16
17 #include "diff_test_utils.h"
18
19 #include "source/opt/build_module.h"
20 #include "source/opt/ir_context.h"
21 #include "source/spirv_constant.h"
22 #include "spirv-tools/libspirv.hpp"
23 #include "tools/util/cli_consumer.h"
24
25 #include <fstream>
26 #include <string>
27
28 #include "gtest/gtest.h"
29
30 namespace spvtools {
31 namespace diff {
32 namespace {
33
34 constexpr auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_6;
35
Assemble(const std::string & spirv)36 std::unique_ptr<spvtools::opt::IRContext> Assemble(const std::string& spirv) {
37 spvtools::SpirvTools t(kDefaultEnvironment);
38 t.SetMessageConsumer(spvtools::utils::CLIMessageConsumer);
39 std::vector<uint32_t> binary;
40 if (!t.Assemble(spirv, &binary,
41 spvtools::SpirvTools::kDefaultAssembleOption |
42 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS))
43 return nullptr;
44 return spvtools::BuildModule(kDefaultEnvironment,
45 spvtools::utils::CLIMessageConsumer,
46 binary.data(), binary.size());
47 }
48
TEST(DiffIndentTest,Diff)49 TEST(DiffIndentTest, Diff) {
50 const std::string src = R"(OpCapability Shader
51 %ext_inst = OpExtInstImport "GLSL.std.450"
52 OpMemoryModel Logical GLSL450
53 OpEntryPoint Fragment %main "main"
54 OpExecutionMode %main OriginUpperLeft
55 %void = OpTypeVoid
56 %func = OpTypeFunction %void
57
58 %main = OpFunction %void None %func
59 %main_entry = OpLabel
60 OpReturn
61 OpFunctionEnd;)";
62
63 const std::string dst = R"(OpCapability Shader
64 OpMemoryModel Logical GLSL450
65 OpEntryPoint Fragment %main "main"
66 OpExecutionMode %main OriginUpperLeft
67 %void = OpTypeVoid
68 %func = OpTypeFunction %void
69
70 %main = OpFunction %void None %func
71 %main_entry = OpLabel
72 OpReturn
73 OpFunctionEnd;)";
74
75 const std::string diff = R"( ; SPIR-V
76 ; Version: 1.6
77 ; Generator: Khronos SPIR-V Tools Assembler; 0
78 ; Bound: 6
79 ; Schema: 0
80 OpCapability Shader
81 - %1 = OpExtInstImport "GLSL.std.450"
82 OpMemoryModel Logical GLSL450
83 OpEntryPoint Fragment %2 "main"
84 OpExecutionMode %2 OriginUpperLeft
85 %3 = OpTypeVoid
86 %4 = OpTypeFunction %3
87 %2 = OpFunction %3 None %4
88 %5 = OpLabel
89 OpReturn
90 OpFunctionEnd
91 )";
92
93 Options options;
94 options.indent = true;
95 DoStringDiffTest(src, dst, diff, options);
96 }
97
TEST(DiffNoHeaderTest,Diff)98 TEST(DiffNoHeaderTest, Diff) {
99 const std::string src = R"(OpCapability Shader
100 %ext_inst = OpExtInstImport "GLSL.std.450"
101 OpMemoryModel Logical GLSL450
102 OpEntryPoint Fragment %main "main"
103 OpExecutionMode %main OriginUpperLeft
104 %void = OpTypeVoid
105 %func = OpTypeFunction %void
106
107 %main = OpFunction %void None %func
108 %main_entry = OpLabel
109 OpReturn
110 OpFunctionEnd;)";
111
112 const std::string dst = R"(OpCapability Shader
113 OpMemoryModel Logical GLSL450
114 OpEntryPoint Fragment %main "main"
115 OpExecutionMode %main OriginUpperLeft
116 %void = OpTypeVoid
117 %func = OpTypeFunction %void
118
119 %main = OpFunction %void None %func
120 %main_entry = OpLabel
121 OpReturn
122 OpFunctionEnd;)";
123
124 const std::string diff = R"( OpCapability Shader
125 -%1 = OpExtInstImport "GLSL.std.450"
126 OpMemoryModel Logical GLSL450
127 OpEntryPoint Fragment %2 "main"
128 OpExecutionMode %2 OriginUpperLeft
129 %3 = OpTypeVoid
130 %4 = OpTypeFunction %3
131 %2 = OpFunction %3 None %4
132 %5 = OpLabel
133 OpReturn
134 OpFunctionEnd
135 )";
136
137 Options options;
138 options.no_header = true;
139 DoStringDiffTest(src, dst, diff, options);
140 }
141
TEST(DiffHeaderTest,Diff)142 TEST(DiffHeaderTest, Diff) {
143 const std::string src_spirv = R"(OpCapability Shader
144 %ext_inst = OpExtInstImport "GLSL.std.450"
145 OpMemoryModel Logical GLSL450
146 OpEntryPoint Fragment %main "main"
147 OpExecutionMode %main OriginUpperLeft
148 %void = OpTypeVoid
149 %func = OpTypeFunction %void
150
151 %main = OpFunction %void None %func
152 %main_entry = OpLabel
153 OpReturn
154 OpFunctionEnd;)";
155
156 const std::string dst_spirv = R"(OpCapability Shader
157 OpMemoryModel Logical GLSL450
158 OpEntryPoint Fragment %main "main"
159 OpExecutionMode %main OriginUpperLeft
160 %void = OpTypeVoid
161 %func = OpTypeFunction %void
162
163 %main = OpFunction %void None %func
164 %main_entry = OpLabel
165 OpReturn
166 OpFunctionEnd;)";
167
168 const std::string diff = R"( ; SPIR-V
169 -; Version: 1.3
170 +; Version: 1.2
171 -; Generator: Khronos SPIR-V Tools Assembler; 3
172 +; Generator: Khronos Glslang Reference Front End; 10
173 ; Bound: 6
174 ; Schema: 0
175 OpCapability Shader
176 -%1 = OpExtInstImport "GLSL.std.450"
177 OpMemoryModel Logical GLSL450
178 OpEntryPoint Fragment %2 "main"
179 OpExecutionMode %2 OriginUpperLeft
180 %3 = OpTypeVoid
181 %4 = OpTypeFunction %3
182 %2 = OpFunction %3 None %4
183 %5 = OpLabel
184 OpReturn
185 OpFunctionEnd
186 )";
187
188 // Load the src and dst modules
189 std::unique_ptr<spvtools::opt::IRContext> src = Assemble(src_spirv);
190 ASSERT_TRUE(src);
191
192 std::unique_ptr<spvtools::opt::IRContext> dst = Assemble(dst_spirv);
193 ASSERT_TRUE(dst);
194
195 // Differentiate them in the header.
196 const spvtools::opt::ModuleHeader src_header = {
197 spv::MagicNumber,
198 SPV_SPIRV_VERSION_WORD(1, 3),
199 SPV_GENERATOR_WORD(SPV_GENERATOR_KHRONOS_ASSEMBLER, 3),
200 src->module()->IdBound(),
201 src->module()->schema(),
202 };
203 const spvtools::opt::ModuleHeader dst_header = {
204 spv::MagicNumber,
205 SPV_SPIRV_VERSION_WORD(1, 2),
206 SPV_GENERATOR_WORD(SPV_GENERATOR_KHRONOS_GLSLANG, 10),
207 dst->module()->IdBound(),
208 dst->module()->schema(),
209 };
210
211 src->module()->SetHeader(src_header);
212 dst->module()->SetHeader(dst_header);
213
214 // Take the diff
215 Options options;
216 std::ostringstream diff_result;
217 spv_result_t result =
218 spvtools::diff::Diff(src.get(), dst.get(), diff_result, options);
219 ASSERT_EQ(result, SPV_SUCCESS);
220
221 // Expect they match
222 EXPECT_EQ(diff_result.str(), diff);
223 }
224
225 } // namespace
226 } // namespace diff
227 } // namespace spvtools
228