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
25 const uint32_t binary_count = 2u;
26
27 class EntryPointsAmountTest : public spvtest::LinkerTest {
28 public:
EntryPointsAmountTest()29 EntryPointsAmountTest() { binaries.reserve(binary_count + 1u); }
30
SetUp()31 void SetUp() override {
32 const uint32_t global_variable_count_per_binary =
33 (SPV_LIMIT_GLOBAL_VARIABLES_MAX - 1u) / binary_count;
34
35 spvtest::Binary common_binary = {
36 // clang-format off
37 static_cast<uint32_t>(spv::MagicNumber),
38 static_cast<uint32_t>(spv::Version),
39 SPV_GENERATOR_WORD(SPV_GENERATOR_KHRONOS, 0),
40 3u + global_variable_count_per_binary, // NOTE: Bound
41 0u, // NOTE: Schema; reserved
42
43 static_cast<uint32_t>(spv::Op::OpCapability) | 2u << spv::WordCountShift,
44 static_cast<uint32_t>(spv::Capability::Shader),
45
46 static_cast<uint32_t>(spv::Op::OpMemoryModel) | 3u << spv::WordCountShift,
47 static_cast<uint32_t>(spv::AddressingModel::Logical),
48 static_cast<uint32_t>(spv::MemoryModel::Simple),
49
50 static_cast<uint32_t>(spv::Op::OpTypeFloat) | 3u << spv::WordCountShift,
51 1u, // NOTE: Result ID
52 32u, // NOTE: Width
53
54 static_cast<uint32_t>(spv::Op::OpTypePointer) | 4u << spv::WordCountShift,
55 2u, // NOTE: Result ID
56 static_cast<uint32_t>(spv::StorageClass::Input),
57 1u // NOTE: Type ID
58 // clang-format on
59 };
60
61 binaries.push_back({});
62 spvtest::Binary& binary = binaries.back();
63 binary.reserve(common_binary.size() + global_variable_count_per_binary * 4);
64 binary.insert(binary.end(), common_binary.cbegin(), common_binary.cend());
65
66 for (uint32_t i = 0u; i < global_variable_count_per_binary; ++i) {
67 binary.push_back(static_cast<uint32_t>(spv::Op::OpVariable) |
68 4u << spv::WordCountShift);
69 binary.push_back(2u); // NOTE: Type ID
70 binary.push_back(3u + i); // NOTE: Result ID
71 binary.push_back(static_cast<uint32_t>(spv::StorageClass::Input));
72 }
73
74 for (uint32_t i = 0u; i < binary_count - 1u; ++i) {
75 binaries.push_back(binaries.back());
76 }
77 }
TearDown()78 void TearDown() override { binaries.clear(); }
79
80 spvtest::Binaries binaries;
81 };
82
TEST_F(EntryPointsAmountTest,UnderLimit)83 TEST_F(EntryPointsAmountTest, UnderLimit) {
84 spvtest::Binary linked_binary;
85
86 ASSERT_EQ(SPV_SUCCESS, Link(binaries, &linked_binary)) << GetErrorMessage();
87 EXPECT_THAT(GetErrorMessage(), std::string());
88 }
89
TEST_F(EntryPointsAmountTest,OverLimit)90 TEST_F(EntryPointsAmountTest, OverLimit) {
91 binaries.push_back({
92 // clang-format off
93 static_cast<uint32_t>(spv::MagicNumber),
94 static_cast<uint32_t>(spv::Version),
95 SPV_GENERATOR_WORD(SPV_GENERATOR_KHRONOS, 0),
96 5u, // NOTE: Bound
97 0u, // NOTE: Schema; reserved
98
99 static_cast<uint32_t>(spv::Op::OpCapability) | 2u << spv::WordCountShift,
100 static_cast<uint32_t>(spv::Capability::Shader),
101
102 static_cast<uint32_t>(spv::Op::OpMemoryModel) | 3u << spv::WordCountShift,
103 static_cast<uint32_t>(spv::AddressingModel::Logical),
104 static_cast<uint32_t>(spv::MemoryModel::Simple),
105
106 static_cast<uint32_t>(spv::Op::OpTypeFloat) | 3u << spv::WordCountShift,
107 1u, // NOTE: Result ID
108 32u, // NOTE: Width
109
110 static_cast<uint32_t>(spv::Op::OpTypePointer) | 4u << spv::WordCountShift,
111 2u, // NOTE: Result ID
112 static_cast<uint32_t>(spv::StorageClass::Input),
113 1u, // NOTE: Type ID
114
115 static_cast<uint32_t>(spv::Op::OpVariable) | 4u << spv::WordCountShift,
116 2u, // NOTE: Type ID
117 3u, // NOTE: Result ID
118 static_cast<uint32_t>(spv::StorageClass::Input),
119
120 static_cast<uint32_t>(spv::Op::OpVariable) | 4u << spv::WordCountShift,
121 2u, // NOTE: Type ID
122 4u, // NOTE: Result ID
123 static_cast<uint32_t>(spv::StorageClass::Input)
124 // clang-format on
125 });
126
127 spvtest::Binary linked_binary;
128 ASSERT_EQ(SPV_SUCCESS, Link(binaries, &linked_binary)) << GetErrorMessage();
129 EXPECT_THAT(
130 GetErrorMessage(),
131 HasSubstr("The minimum limit of global values, 65535, was exceeded; "
132 "65536 global values were found."));
133 }
134
135 } // namespace
136 } // namespace spvtools
137