1 // Copyright (c) 2017 Pierre Moreau
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 "gmock/gmock.h"
18 #include "test/link/linker_fixture.h"
19
20 namespace spvtools {
21 namespace {
22
23 using ::testing::HasSubstr;
24 using MatchingImportsToExports = spvtest::LinkerTest;
25
TEST_F(MatchingImportsToExports,Default)26 TEST_F(MatchingImportsToExports, Default) {
27 const std::string body1 = R"(
28 OpCapability Linkage
29 OpCapability Addresses
30 OpCapability Kernel
31 OpMemoryModel Physical64 OpenCL
32 OpDecorate %1 LinkageAttributes "foo" Import
33 %2 = OpTypeFloat 32
34 %1 = OpVariable %2 Uniform
35 %3 = OpVariable %2 Input
36 )";
37 const std::string body2 = R"(
38 OpCapability Linkage
39 OpCapability Addresses
40 OpCapability Kernel
41 OpMemoryModel Physical64 OpenCL
42 OpDecorate %1 LinkageAttributes "foo" Export
43 %2 = OpTypeFloat 32
44 %3 = OpConstant %2 42
45 %1 = OpVariable %2 Uniform %3
46 )";
47
48 spvtest::Binary linked_binary;
49 ASSERT_EQ(SPV_SUCCESS, AssembleAndLink({body1, body2}, &linked_binary))
50 << GetErrorMessage();
51
52 const std::string expected_res =
53 R"(OpCapability Addresses
54 OpCapability Kernel
55 OpMemoryModel Physical64 OpenCL
56 OpModuleProcessed "Linked by SPIR-V Tools Linker"
57 %1 = OpTypeFloat 32
58 %2 = OpVariable %1 Input
59 %3 = OpConstant %1 42
60 %4 = OpVariable %1 Uniform %3
61 )";
62 std::string res_body;
63 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
64 ASSERT_EQ(SPV_SUCCESS, Disassemble(linked_binary, &res_body))
65 << GetErrorMessage();
66 EXPECT_EQ(expected_res, res_body);
67 }
68
TEST_F(MatchingImportsToExports,NotALibraryExtraExports)69 TEST_F(MatchingImportsToExports, NotALibraryExtraExports) {
70 const std::string body = R"(
71 OpCapability Linkage
72 OpCapability Addresses
73 OpCapability Kernel
74 OpMemoryModel Physical64 OpenCL
75 OpDecorate %1 LinkageAttributes "foo" Export
76 %2 = OpTypeFloat 32
77 %1 = OpVariable %2 Uniform
78 )";
79
80 spvtest::Binary linked_binary;
81 ASSERT_EQ(SPV_SUCCESS, AssembleAndLink({body}, &linked_binary))
82 << GetErrorMessage();
83
84 const std::string expected_res =
85 R"(OpCapability Addresses
86 OpCapability Kernel
87 OpMemoryModel Physical64 OpenCL
88 OpModuleProcessed "Linked by SPIR-V Tools Linker"
89 %1 = OpTypeFloat 32
90 %2 = OpVariable %1 Uniform
91 )";
92 std::string res_body;
93 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
94 ASSERT_EQ(SPV_SUCCESS, Disassemble(linked_binary, &res_body))
95 << GetErrorMessage();
96 EXPECT_EQ(expected_res, res_body);
97 }
98
TEST_F(MatchingImportsToExports,LibraryExtraExports)99 TEST_F(MatchingImportsToExports, LibraryExtraExports) {
100 const std::string body = R"(
101 OpCapability Linkage
102 OpCapability Addresses
103 OpCapability Kernel
104 OpMemoryModel Physical64 OpenCL
105 OpDecorate %1 LinkageAttributes "foo" Export
106 %2 = OpTypeFloat 32
107 %1 = OpVariable %2 Uniform
108 )";
109
110 spvtest::Binary linked_binary;
111 LinkerOptions options;
112 options.SetCreateLibrary(true);
113 ASSERT_EQ(SPV_SUCCESS, AssembleAndLink({body}, &linked_binary, options))
114 << GetErrorMessage();
115
116 const std::string expected_res = R"(OpCapability Linkage
117 OpCapability Addresses
118 OpCapability Kernel
119 OpMemoryModel Physical64 OpenCL
120 OpModuleProcessed "Linked by SPIR-V Tools Linker"
121 OpDecorate %1 LinkageAttributes "foo" Export
122 %2 = OpTypeFloat 32
123 %1 = OpVariable %2 Uniform
124 )";
125 std::string res_body;
126 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
127 ASSERT_EQ(SPV_SUCCESS, Disassemble(linked_binary, &res_body))
128 << GetErrorMessage();
129 EXPECT_EQ(expected_res, res_body);
130 }
131
TEST_F(MatchingImportsToExports,UnresolvedImports)132 TEST_F(MatchingImportsToExports, UnresolvedImports) {
133 const std::string body1 = R"(
134 OpCapability Linkage
135 OpCapability Addresses
136 OpCapability Kernel
137 OpMemoryModel Physical64 OpenCL
138 OpDecorate %1 LinkageAttributes "foo" Import
139 %2 = OpTypeFloat 32
140 %1 = OpVariable %2 Uniform
141 )";
142 const std::string body2 = R"(
143 OpCapability Addresses
144 OpCapability Kernel
145 OpMemoryModel Physical64 OpenCL
146 )";
147
148 spvtest::Binary linked_binary;
149 EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
150 AssembleAndLink({body1, body2}, &linked_binary));
151 EXPECT_THAT(GetErrorMessage(),
152 HasSubstr("Unresolved external reference to \"foo\"."));
153 }
154
TEST_F(MatchingImportsToExports,TypeMismatch)155 TEST_F(MatchingImportsToExports, TypeMismatch) {
156 const std::string body1 = R"(
157 OpCapability Linkage
158 OpCapability Addresses
159 OpCapability Kernel
160 OpMemoryModel Physical64 OpenCL
161 OpDecorate %1 LinkageAttributes "foo" Import
162 %2 = OpTypeFloat 32
163 %1 = OpVariable %2 Uniform
164 %3 = OpVariable %2 Input
165 )";
166 const std::string body2 = R"(
167 OpCapability Linkage
168 OpCapability Addresses
169 OpCapability Kernel
170 OpMemoryModel Physical64 OpenCL
171 OpDecorate %1 LinkageAttributes "foo" Export
172 %2 = OpTypeInt 32 0
173 %3 = OpConstant %2 42
174 %1 = OpVariable %2 Uniform %3
175 )";
176
177 spvtest::Binary linked_binary;
178 EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
179 AssembleAndLink({body1, body2}, &linked_binary))
180 << GetErrorMessage();
181 EXPECT_THAT(
182 GetErrorMessage(),
183 HasSubstr("Type mismatch on symbol \"foo\" between imported "
184 "variable/function %1 and exported variable/function %4"));
185 }
186
TEST_F(MatchingImportsToExports,MultipleDefinitions)187 TEST_F(MatchingImportsToExports, MultipleDefinitions) {
188 const std::string body1 = R"(
189 OpCapability Linkage
190 OpCapability Addresses
191 OpCapability Kernel
192 OpMemoryModel Physical64 OpenCL
193 OpDecorate %1 LinkageAttributes "foo" Import
194 %2 = OpTypeFloat 32
195 %1 = OpVariable %2 Uniform
196 %3 = OpVariable %2 Input
197 )";
198 const std::string body2 = R"(
199 OpCapability Linkage
200 OpCapability Addresses
201 OpCapability Kernel
202 OpMemoryModel Physical64 OpenCL
203 OpDecorate %1 LinkageAttributes "foo" Export
204 %2 = OpTypeFloat 32
205 %3 = OpConstant %2 42
206 %1 = OpVariable %2 Uniform %3
207 )";
208 const std::string body3 = R"(
209 OpCapability Linkage
210 OpCapability Addresses
211 OpCapability Kernel
212 OpMemoryModel Physical64 OpenCL
213 OpDecorate %1 LinkageAttributes "foo" Export
214 %2 = OpTypeFloat 32
215 %3 = OpConstant %2 -1
216 %1 = OpVariable %2 Uniform %3
217 )";
218
219 spvtest::Binary linked_binary;
220 EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
221 AssembleAndLink({body1, body2, body3}, &linked_binary))
222 << GetErrorMessage();
223 EXPECT_THAT(GetErrorMessage(),
224 HasSubstr("Too many external references, 2, were found "
225 "for \"foo\"."));
226 }
227
TEST_F(MatchingImportsToExports,SameNameDifferentTypes)228 TEST_F(MatchingImportsToExports, SameNameDifferentTypes) {
229 const std::string body1 = R"(
230 OpCapability Linkage
231 OpCapability Addresses
232 OpCapability Kernel
233 OpMemoryModel Physical64 OpenCL
234 OpDecorate %1 LinkageAttributes "foo" Import
235 %2 = OpTypeFloat 32
236 %1 = OpVariable %2 Uniform
237 %3 = OpVariable %2 Input
238 )";
239 const std::string body2 = R"(
240 OpCapability Linkage
241 OpCapability Addresses
242 OpCapability Kernel
243 OpMemoryModel Physical64 OpenCL
244 OpDecorate %1 LinkageAttributes "foo" Export
245 %2 = OpTypeInt 32 0
246 %3 = OpConstant %2 42
247 %1 = OpVariable %2 Uniform %3
248 )";
249 const std::string body3 = R"(
250 OpCapability Linkage
251 OpCapability Addresses
252 OpCapability Kernel
253 OpMemoryModel Physical64 OpenCL
254 OpDecorate %1 LinkageAttributes "foo" Export
255 %2 = OpTypeFloat 32
256 %3 = OpConstant %2 12
257 %1 = OpVariable %2 Uniform %3
258 )";
259
260 spvtest::Binary linked_binary;
261 EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
262 AssembleAndLink({body1, body2, body3}, &linked_binary))
263 << GetErrorMessage();
264 EXPECT_THAT(GetErrorMessage(),
265 HasSubstr("Too many external references, 2, were found "
266 "for \"foo\"."));
267 }
268
TEST_F(MatchingImportsToExports,DecorationMismatch)269 TEST_F(MatchingImportsToExports, DecorationMismatch) {
270 const std::string body1 = R"(
271 OpCapability Linkage
272 OpCapability Addresses
273 OpCapability Kernel
274 OpMemoryModel Physical64 OpenCL
275 OpDecorate %1 LinkageAttributes "foo" Import
276 OpDecorate %2 Constant
277 %2 = OpTypeFloat 32
278 %1 = OpVariable %2 Uniform
279 %3 = OpVariable %2 Input
280 )";
281 const std::string body2 = R"(
282 OpCapability Linkage
283 OpCapability Addresses
284 OpCapability Kernel
285 OpMemoryModel Physical64 OpenCL
286 OpDecorate %1 LinkageAttributes "foo" Export
287 %2 = OpTypeFloat 32
288 %3 = OpConstant %2 42
289 %1 = OpVariable %2 Uniform %3
290 )";
291
292 spvtest::Binary linked_binary;
293 EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
294 AssembleAndLink({body1, body2}, &linked_binary))
295 << GetErrorMessage();
296 EXPECT_THAT(
297 GetErrorMessage(),
298 HasSubstr("Type mismatch on symbol \"foo\" between imported "
299 "variable/function %1 and exported variable/function %4"));
300 }
301
TEST_F(MatchingImportsToExports,FuncParamAttrDifferButStillMatchExportToImport)302 TEST_F(MatchingImportsToExports,
303 FuncParamAttrDifferButStillMatchExportToImport) {
304 const std::string body1 = R"(
305 OpCapability Linkage
306 OpCapability Addresses
307 OpCapability Kernel
308 OpMemoryModel Physical64 OpenCL
309 OpDecorate %1 LinkageAttributes "foo" Import
310 OpDecorate %2 FuncParamAttr Zext
311 %3 = OpTypeVoid
312 %4 = OpTypeInt 32 0
313 %5 = OpTypeFunction %3 %4
314 %1 = OpFunction %3 None %5
315 %2 = OpFunctionParameter %4
316 OpFunctionEnd
317 )";
318 const std::string body2 = R"(
319 OpCapability Linkage
320 OpCapability Addresses
321 OpCapability Kernel
322 OpMemoryModel Physical64 OpenCL
323 OpDecorate %1 LinkageAttributes "foo" Export
324 OpDecorate %2 FuncParamAttr Sext
325 %3 = OpTypeVoid
326 %4 = OpTypeInt 32 0
327 %5 = OpTypeFunction %3 %4
328 %1 = OpFunction %3 None %5
329 %2 = OpFunctionParameter %4
330 %6 = OpLabel
331 OpReturn
332 OpFunctionEnd
333 )";
334
335 spvtest::Binary linked_binary;
336 ASSERT_EQ(SPV_SUCCESS, AssembleAndLink({body1, body2}, &linked_binary))
337 << GetErrorMessage();
338
339 const std::string expected_res = R"(OpCapability Addresses
340 OpCapability Kernel
341 OpMemoryModel Physical64 OpenCL
342 OpModuleProcessed "Linked by SPIR-V Tools Linker"
343 OpDecorate %1 FuncParamAttr Sext
344 %2 = OpTypeVoid
345 %3 = OpTypeInt 32 0
346 %4 = OpTypeFunction %2 %3
347 %5 = OpFunction %2 None %4
348 %1 = OpFunctionParameter %3
349 %6 = OpLabel
350 OpReturn
351 OpFunctionEnd
352 )";
353 std::string res_body;
354 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
355 ASSERT_EQ(SPV_SUCCESS, Disassemble(linked_binary, &res_body))
356 << GetErrorMessage();
357 EXPECT_EQ(expected_res, res_body);
358 }
359
TEST_F(MatchingImportsToExports,FunctionCtrl)360 TEST_F(MatchingImportsToExports, FunctionCtrl) {
361 const std::string body1 = R"(
362 OpCapability Linkage
363 OpCapability Addresses
364 OpCapability Kernel
365 OpMemoryModel Physical64 OpenCL
366 OpDecorate %1 LinkageAttributes "foo" Import
367 %2 = OpTypeVoid
368 %3 = OpTypeFunction %2
369 %4 = OpTypeFloat 32
370 %5 = OpVariable %4 Uniform
371 %1 = OpFunction %2 None %3
372 OpFunctionEnd
373 )";
374 const std::string body2 = R"(
375 OpCapability Linkage
376 OpCapability Addresses
377 OpCapability Kernel
378 OpMemoryModel Physical64 OpenCL
379 OpDecorate %1 LinkageAttributes "foo" Export
380 %2 = OpTypeVoid
381 %3 = OpTypeFunction %2
382 %1 = OpFunction %2 Inline %3
383 %4 = OpLabel
384 OpReturn
385 OpFunctionEnd
386 )";
387
388 spvtest::Binary linked_binary;
389 ASSERT_EQ(SPV_SUCCESS, AssembleAndLink({body1, body2}, &linked_binary))
390 << GetErrorMessage();
391
392 const std::string expected_res =
393 R"(OpCapability Addresses
394 OpCapability Kernel
395 OpMemoryModel Physical64 OpenCL
396 OpModuleProcessed "Linked by SPIR-V Tools Linker"
397 %1 = OpTypeVoid
398 %2 = OpTypeFunction %1
399 %3 = OpTypeFloat 32
400 %4 = OpVariable %3 Uniform
401 %5 = OpFunction %1 Inline %2
402 %6 = OpLabel
403 OpReturn
404 OpFunctionEnd
405 )";
406 std::string res_body;
407 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
408 ASSERT_EQ(SPV_SUCCESS, Disassemble(linked_binary, &res_body))
409 << GetErrorMessage();
410 EXPECT_EQ(expected_res, res_body);
411 }
412
TEST_F(MatchingImportsToExports,UseExportedFuncParamAttr)413 TEST_F(MatchingImportsToExports, UseExportedFuncParamAttr) {
414 const std::string body1 = R"(
415 OpCapability Linkage
416 OpCapability Addresses
417 OpCapability Kernel
418 OpMemoryModel Physical64 OpenCL
419 OpDecorate %1 LinkageAttributes "foo" Import
420 OpDecorate %2 FuncParamAttr Zext
421 %2 = OpDecorationGroup
422 OpGroupDecorate %2 %3 %4
423 %5 = OpTypeVoid
424 %6 = OpTypeInt 32 0
425 %7 = OpTypeFunction %5 %6
426 %1 = OpFunction %5 None %7
427 %3 = OpFunctionParameter %6
428 OpFunctionEnd
429 %8 = OpFunction %5 None %7
430 %4 = OpFunctionParameter %6
431 OpFunctionEnd
432 )";
433 const std::string body2 = R"(
434 OpCapability Linkage
435 OpCapability Addresses
436 OpCapability Kernel
437 OpMemoryModel Physical64 OpenCL
438 OpDecorate %1 LinkageAttributes "foo" Export
439 OpDecorate %2 FuncParamAttr Sext
440 %3 = OpTypeVoid
441 %4 = OpTypeInt 32 0
442 %5 = OpTypeFunction %3 %4
443 %1 = OpFunction %3 None %5
444 %2 = OpFunctionParameter %4
445 %6 = OpLabel
446 OpReturn
447 OpFunctionEnd
448 )";
449
450 spvtest::Binary linked_binary;
451 ASSERT_EQ(SPV_SUCCESS, AssembleAndLink({body1, body2}, &linked_binary))
452 << GetErrorMessage();
453
454 const std::string expected_res = R"(OpCapability Addresses
455 OpCapability Kernel
456 OpMemoryModel Physical64 OpenCL
457 OpModuleProcessed "Linked by SPIR-V Tools Linker"
458 OpDecorate %1 FuncParamAttr Zext
459 %1 = OpDecorationGroup
460 OpGroupDecorate %1 %2
461 OpDecorate %3 FuncParamAttr Sext
462 %4 = OpTypeVoid
463 %5 = OpTypeInt 32 0
464 %6 = OpTypeFunction %4 %5
465 %7 = OpFunction %4 None %6
466 %2 = OpFunctionParameter %5
467 OpFunctionEnd
468 %8 = OpFunction %4 None %6
469 %3 = OpFunctionParameter %5
470 %9 = OpLabel
471 OpReturn
472 OpFunctionEnd
473 )";
474 std::string res_body;
475 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
476 ASSERT_EQ(SPV_SUCCESS, Disassemble(linked_binary, &res_body))
477 << GetErrorMessage();
478 EXPECT_EQ(expected_res, res_body);
479 }
480
TEST_F(MatchingImportsToExports,NamesAndDecorations)481 TEST_F(MatchingImportsToExports, NamesAndDecorations) {
482 const std::string body1 = R"(
483 OpCapability Linkage
484 OpCapability Addresses
485 OpCapability Kernel
486 OpMemoryModel Physical64 OpenCL
487 OpName %1 "foo"
488 OpName %3 "param"
489 OpDecorate %1 LinkageAttributes "foo" Import
490 OpDecorate %2 Restrict
491 OpDecorate %4 NonWritable
492 %2 = OpDecorationGroup
493 OpGroupDecorate %2 %3 %4
494 %5 = OpTypeVoid
495 %6 = OpTypeInt 32 0
496 %9 = OpTypePointer Function %6
497 %7 = OpTypeFunction %5 %9
498 %1 = OpFunction %5 None %7
499 %3 = OpFunctionParameter %9
500 OpFunctionEnd
501 %8 = OpFunction %5 None %7
502 %4 = OpFunctionParameter %9
503 OpFunctionEnd
504 )";
505 const std::string body2 = R"(
506 OpCapability Linkage
507 OpCapability Addresses
508 OpCapability Kernel
509 OpMemoryModel Physical64 OpenCL
510 OpName %1 "foo"
511 OpName %2 "param"
512 OpDecorate %1 LinkageAttributes "foo" Export
513 OpDecorate %2 Restrict
514 %3 = OpTypeVoid
515 %4 = OpTypeInt 32 0
516 %7 = OpTypePointer Function %4
517 %5 = OpTypeFunction %3 %7
518 %1 = OpFunction %3 None %5
519 %2 = OpFunctionParameter %7
520 %6 = OpLabel
521 OpReturn
522 OpFunctionEnd
523 )";
524
525 spvtest::Binary linked_binary;
526 ASSERT_EQ(SPV_SUCCESS, AssembleAndLink({body1, body2}, &linked_binary))
527 << GetErrorMessage();
528
529 const std::string expected_res = R"(OpCapability Addresses
530 OpCapability Kernel
531 OpMemoryModel Physical64 OpenCL
532 OpName %1 "foo"
533 OpName %2 "param"
534 OpModuleProcessed "Linked by SPIR-V Tools Linker"
535 OpDecorate %3 Restrict
536 OpDecorate %4 NonWritable
537 %3 = OpDecorationGroup
538 OpGroupDecorate %3 %4
539 OpDecorate %2 Restrict
540 %5 = OpTypeVoid
541 %6 = OpTypeInt 32 0
542 %7 = OpTypePointer Function %6
543 %8 = OpTypeFunction %5 %7
544 %9 = OpFunction %5 None %8
545 %4 = OpFunctionParameter %7
546 OpFunctionEnd
547 %1 = OpFunction %5 None %8
548 %2 = OpFunctionParameter %7
549 %10 = OpLabel
550 OpReturn
551 OpFunctionEnd
552 )";
553 std::string res_body;
554 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
555 ASSERT_EQ(SPV_SUCCESS, Disassemble(linked_binary, &res_body))
556 << GetErrorMessage();
557 EXPECT_EQ(expected_res, res_body);
558 }
559
560 } // namespace
561 } // namespace spvtools
562