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