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