| // Copyright (c) 2017 Pierre Moreau | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // http://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| #include <string> | |
| #include "gmock/gmock.h" | |
| #include "test/link/linker_fixture.h" | |
| namespace spvtools { | |
| namespace { | |
| using ::testing::HasSubstr; | |
| class IdsLimit : public spvtest::LinkerTest { | |
| public: | |
| IdsLimit() { binaries.reserve(2u); } | |
| void SetUp() override { | |
| const uint32_t id_bound = SPV_LIMIT_RESULT_ID_BOUND - 1u; | |
| const uint32_t constant_count = | |
| id_bound - | |
| 2u; // One ID is used for TypeBool, and (constant_count + 1) < id_bound | |
| // This is needed, as otherwise the ID bound will get reset to 1 while | |
| // running the RemoveDuplicates pass. | |
| spvtest::Binary common_binary = { | |
| // clang-format off | |
| spv::MagicNumber, | |
| spv::Version, | |
| SPV_GENERATOR_WORD(SPV_GENERATOR_KHRONOS, 0), | |
| id_bound, // NOTE: Bound | |
| 0u, // NOTE: Schema; reserved | |
| static_cast<uint32_t>(spv::Op::OpCapability) | 2u << spv::WordCountShift, | |
| static_cast<uint32_t>(spv::Capability::Shader), | |
| static_cast<uint32_t>(spv::Op::OpMemoryModel) | 3u << spv::WordCountShift, | |
| static_cast<uint32_t>(spv::AddressingModel::Logical), | |
| static_cast<uint32_t>(spv::MemoryModel::Simple), | |
| static_cast<uint32_t>(spv::Op::OpTypeBool) | 2u << spv::WordCountShift, | |
| 1u // NOTE: Result ID | |
| // clang-format on | |
| }; | |
| binaries.push_back({}); | |
| spvtest::Binary& binary = binaries.back(); | |
| binary.reserve(common_binary.size() + constant_count * 3u); | |
| binary.insert(binary.end(), common_binary.cbegin(), common_binary.cend()); | |
| for (uint32_t i = 0u; i < constant_count; ++i) { | |
| binary.push_back(static_cast<uint32_t>(spv::Op::OpConstantTrue) | | |
| 3u << spv::WordCountShift); | |
| binary.push_back(1u); // NOTE: Type ID | |
| binary.push_back(2u + i); // NOTE: Result ID | |
| } | |
| } | |
| void TearDown() override { binaries.clear(); } | |
| spvtest::Binaries binaries; | |
| }; | |
| spvtest::Binary CreateBinary(uint32_t id_bound) { | |
| return { | |
| // clang-format off | |
| // Header | |
| spv::MagicNumber, | |
| spv::Version, | |
| SPV_GENERATOR_WORD(SPV_GENERATOR_KHRONOS, 0), | |
| id_bound, // NOTE: Bound | |
| 0u, // NOTE: Schema; reserved | |
| // OpCapability Shader | |
| static_cast<uint32_t>(spv::Op::OpCapability) | 2u << spv::WordCountShift, | |
| static_cast<uint32_t>(spv::Capability::Shader), | |
| // OpMemoryModel Logical Simple | |
| static_cast<uint32_t>(spv::Op::OpMemoryModel) | 3u << spv::WordCountShift, | |
| static_cast<uint32_t>(spv::AddressingModel::Logical), | |
| static_cast<uint32_t>(spv::MemoryModel::Simple) | |
| // clang-format on | |
| }; | |
| } | |
| TEST_F(IdsLimit, DISABLED_UnderLimit) { | |
| spvtest::Binary linked_binary; | |
| ASSERT_EQ(SPV_SUCCESS, Link(binaries, &linked_binary)) << GetErrorMessage(); | |
| EXPECT_THAT(GetErrorMessage(), std::string()); | |
| EXPECT_EQ(0x3FFFFFu, linked_binary[3]); | |
| } | |
| TEST_F(IdsLimit, DISABLED_OverLimit) { | |
| spvtest::Binary& binary = binaries.back(); | |
| const uint32_t id_bound = binary[3]; | |
| binary[3] = id_bound + 1u; | |
| binary.push_back(static_cast<uint32_t>(spv::Op::OpConstantFalse) | | |
| 3u << spv::WordCountShift); | |
| binary.push_back(1u); // NOTE: Type ID | |
| binary.push_back(id_bound); // NOTE: Result ID | |
| spvtest::Binary linked_binary; | |
| ASSERT_EQ(SPV_SUCCESS, Link(binaries, &linked_binary)) << GetErrorMessage(); | |
| EXPECT_THAT( | |
| GetErrorMessage(), | |
| HasSubstr("The minimum limit of IDs, 4194303, was exceeded: 4194304 is " | |
| "the current ID bound.")); | |
| EXPECT_EQ(0x400000u, linked_binary[3]); | |
| } | |
| TEST_F(IdsLimit, DISABLED_Overflow) { | |
| spvtest::Binaries binaries = {CreateBinary(0xFFFFFFFFu), | |
| CreateBinary(0x00000002u)}; | |
| spvtest::Binary linked_binary; | |
| EXPECT_EQ(SPV_ERROR_INVALID_DATA, Link(binaries, &linked_binary)); | |
| EXPECT_THAT( | |
| GetErrorMessage(), | |
| HasSubstr("Too many IDs (4294967296): combining all modules would " | |
| "overflow the 32-bit word of the SPIR-V header.")); | |
| } | |
| } // namespace | |
| } // namespace spvtools |