1fd4e5da5Sopenharmony_ci// Copyright (c) 2017 Pierre Moreau
2fd4e5da5Sopenharmony_ci//
3fd4e5da5Sopenharmony_ci// Licensed under the Apache License, Version 2.0 (the "License");
4fd4e5da5Sopenharmony_ci// you may not use this file except in compliance with the License.
5fd4e5da5Sopenharmony_ci// You may obtain a copy of the License at
6fd4e5da5Sopenharmony_ci//
7fd4e5da5Sopenharmony_ci//     http://www.apache.org/licenses/LICENSE-2.0
8fd4e5da5Sopenharmony_ci//
9fd4e5da5Sopenharmony_ci// Unless required by applicable law or agreed to in writing, software
10fd4e5da5Sopenharmony_ci// distributed under the License is distributed on an "AS IS" BASIS,
11fd4e5da5Sopenharmony_ci// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12fd4e5da5Sopenharmony_ci// See the License for the specific language governing permissions and
13fd4e5da5Sopenharmony_ci// limitations under the License.
14fd4e5da5Sopenharmony_ci
15fd4e5da5Sopenharmony_ci#include <string>
16fd4e5da5Sopenharmony_ci
17fd4e5da5Sopenharmony_ci#include "gmock/gmock.h"
18fd4e5da5Sopenharmony_ci#include "test/link/linker_fixture.h"
19fd4e5da5Sopenharmony_ci
20fd4e5da5Sopenharmony_cinamespace spvtools {
21fd4e5da5Sopenharmony_cinamespace {
22fd4e5da5Sopenharmony_ci
23fd4e5da5Sopenharmony_ciusing ::testing::HasSubstr;
24fd4e5da5Sopenharmony_ci
25fd4e5da5Sopenharmony_ciclass IdsLimit : public spvtest::LinkerTest {
26fd4e5da5Sopenharmony_ci public:
27fd4e5da5Sopenharmony_ci  IdsLimit() { binaries.reserve(2u); }
28fd4e5da5Sopenharmony_ci
29fd4e5da5Sopenharmony_ci  void SetUp() override {
30fd4e5da5Sopenharmony_ci    const uint32_t id_bound = SPV_LIMIT_RESULT_ID_BOUND - 1u;
31fd4e5da5Sopenharmony_ci    const uint32_t constant_count =
32fd4e5da5Sopenharmony_ci        id_bound -
33fd4e5da5Sopenharmony_ci        2u;  // One ID is used for TypeBool, and (constant_count + 1) < id_bound
34fd4e5da5Sopenharmony_ci
35fd4e5da5Sopenharmony_ci    // This is needed, as otherwise the ID bound will get reset to 1 while
36fd4e5da5Sopenharmony_ci    // running the RemoveDuplicates pass.
37fd4e5da5Sopenharmony_ci    spvtest::Binary common_binary = {
38fd4e5da5Sopenharmony_ci        // clang-format off
39fd4e5da5Sopenharmony_ci        spv::MagicNumber,
40fd4e5da5Sopenharmony_ci        spv::Version,
41fd4e5da5Sopenharmony_ci        SPV_GENERATOR_WORD(SPV_GENERATOR_KHRONOS, 0),
42fd4e5da5Sopenharmony_ci        id_bound,  // NOTE: Bound
43fd4e5da5Sopenharmony_ci        0u,        // NOTE: Schema; reserved
44fd4e5da5Sopenharmony_ci
45fd4e5da5Sopenharmony_ci        static_cast<uint32_t>(spv::Op::OpCapability) | 2u << spv::WordCountShift,
46fd4e5da5Sopenharmony_ci        static_cast<uint32_t>(spv::Capability::Shader),
47fd4e5da5Sopenharmony_ci
48fd4e5da5Sopenharmony_ci        static_cast<uint32_t>(spv::Op::OpMemoryModel) | 3u << spv::WordCountShift,
49fd4e5da5Sopenharmony_ci        static_cast<uint32_t>(spv::AddressingModel::Logical),
50fd4e5da5Sopenharmony_ci        static_cast<uint32_t>(spv::MemoryModel::Simple),
51fd4e5da5Sopenharmony_ci
52fd4e5da5Sopenharmony_ci        static_cast<uint32_t>(spv::Op::OpTypeBool) | 2u << spv::WordCountShift,
53fd4e5da5Sopenharmony_ci        1u    // NOTE: Result ID
54fd4e5da5Sopenharmony_ci        // clang-format on
55fd4e5da5Sopenharmony_ci    };
56fd4e5da5Sopenharmony_ci
57fd4e5da5Sopenharmony_ci    binaries.push_back({});
58fd4e5da5Sopenharmony_ci    spvtest::Binary& binary = binaries.back();
59fd4e5da5Sopenharmony_ci    binary.reserve(common_binary.size() + constant_count * 3u);
60fd4e5da5Sopenharmony_ci    binary.insert(binary.end(), common_binary.cbegin(), common_binary.cend());
61fd4e5da5Sopenharmony_ci
62fd4e5da5Sopenharmony_ci    for (uint32_t i = 0u; i < constant_count; ++i) {
63fd4e5da5Sopenharmony_ci      binary.push_back(static_cast<uint32_t>(spv::Op::OpConstantTrue) |
64fd4e5da5Sopenharmony_ci                       3u << spv::WordCountShift);
65fd4e5da5Sopenharmony_ci      binary.push_back(1u);      // NOTE: Type ID
66fd4e5da5Sopenharmony_ci      binary.push_back(2u + i);  // NOTE: Result ID
67fd4e5da5Sopenharmony_ci    }
68fd4e5da5Sopenharmony_ci  }
69fd4e5da5Sopenharmony_ci  void TearDown() override { binaries.clear(); }
70fd4e5da5Sopenharmony_ci
71fd4e5da5Sopenharmony_ci  spvtest::Binaries binaries;
72fd4e5da5Sopenharmony_ci};
73fd4e5da5Sopenharmony_ci
74fd4e5da5Sopenharmony_cispvtest::Binary CreateBinary(uint32_t id_bound) {
75fd4e5da5Sopenharmony_ci  return {
76fd4e5da5Sopenharmony_ci      // clang-format off
77fd4e5da5Sopenharmony_ci      // Header
78fd4e5da5Sopenharmony_ci      spv::MagicNumber,
79fd4e5da5Sopenharmony_ci      spv::Version,
80fd4e5da5Sopenharmony_ci      SPV_GENERATOR_WORD(SPV_GENERATOR_KHRONOS, 0),
81fd4e5da5Sopenharmony_ci      id_bound,  // NOTE: Bound
82fd4e5da5Sopenharmony_ci      0u,        // NOTE: Schema; reserved
83fd4e5da5Sopenharmony_ci
84fd4e5da5Sopenharmony_ci      // OpCapability Shader
85fd4e5da5Sopenharmony_ci      static_cast<uint32_t>(spv::Op::OpCapability) | 2u << spv::WordCountShift,
86fd4e5da5Sopenharmony_ci      static_cast<uint32_t>(spv::Capability::Shader),
87fd4e5da5Sopenharmony_ci
88fd4e5da5Sopenharmony_ci      // OpMemoryModel Logical Simple
89fd4e5da5Sopenharmony_ci      static_cast<uint32_t>(spv::Op::OpMemoryModel) | 3u << spv::WordCountShift,
90fd4e5da5Sopenharmony_ci      static_cast<uint32_t>(spv::AddressingModel::Logical),
91fd4e5da5Sopenharmony_ci      static_cast<uint32_t>(spv::MemoryModel::Simple)
92fd4e5da5Sopenharmony_ci      // clang-format on
93fd4e5da5Sopenharmony_ci  };
94fd4e5da5Sopenharmony_ci}
95fd4e5da5Sopenharmony_ci
96fd4e5da5Sopenharmony_ciTEST_F(IdsLimit, DISABLED_UnderLimit) {
97fd4e5da5Sopenharmony_ci  spvtest::Binary linked_binary;
98fd4e5da5Sopenharmony_ci  ASSERT_EQ(SPV_SUCCESS, Link(binaries, &linked_binary)) << GetErrorMessage();
99fd4e5da5Sopenharmony_ci  EXPECT_THAT(GetErrorMessage(), std::string());
100fd4e5da5Sopenharmony_ci  EXPECT_EQ(0x3FFFFFu, linked_binary[3]);
101fd4e5da5Sopenharmony_ci}
102fd4e5da5Sopenharmony_ci
103fd4e5da5Sopenharmony_ciTEST_F(IdsLimit, DISABLED_OverLimit) {
104fd4e5da5Sopenharmony_ci  spvtest::Binary& binary = binaries.back();
105fd4e5da5Sopenharmony_ci
106fd4e5da5Sopenharmony_ci  const uint32_t id_bound = binary[3];
107fd4e5da5Sopenharmony_ci  binary[3] = id_bound + 1u;
108fd4e5da5Sopenharmony_ci
109fd4e5da5Sopenharmony_ci  binary.push_back(static_cast<uint32_t>(spv::Op::OpConstantFalse) |
110fd4e5da5Sopenharmony_ci                   3u << spv::WordCountShift);
111fd4e5da5Sopenharmony_ci  binary.push_back(1u);        // NOTE: Type ID
112fd4e5da5Sopenharmony_ci  binary.push_back(id_bound);  // NOTE: Result ID
113fd4e5da5Sopenharmony_ci
114fd4e5da5Sopenharmony_ci  spvtest::Binary linked_binary;
115fd4e5da5Sopenharmony_ci  ASSERT_EQ(SPV_SUCCESS, Link(binaries, &linked_binary)) << GetErrorMessage();
116fd4e5da5Sopenharmony_ci  EXPECT_THAT(
117fd4e5da5Sopenharmony_ci      GetErrorMessage(),
118fd4e5da5Sopenharmony_ci      HasSubstr("The minimum limit of IDs, 4194303, was exceeded: 4194304 is "
119fd4e5da5Sopenharmony_ci                "the current ID bound."));
120fd4e5da5Sopenharmony_ci  EXPECT_EQ(0x400000u, linked_binary[3]);
121fd4e5da5Sopenharmony_ci}
122fd4e5da5Sopenharmony_ci
123fd4e5da5Sopenharmony_ciTEST_F(IdsLimit, DISABLED_Overflow) {
124fd4e5da5Sopenharmony_ci  spvtest::Binaries binaries = {CreateBinary(0xFFFFFFFFu),
125fd4e5da5Sopenharmony_ci                                CreateBinary(0x00000002u)};
126fd4e5da5Sopenharmony_ci
127fd4e5da5Sopenharmony_ci  spvtest::Binary linked_binary;
128fd4e5da5Sopenharmony_ci
129fd4e5da5Sopenharmony_ci  EXPECT_EQ(SPV_ERROR_INVALID_DATA, Link(binaries, &linked_binary));
130fd4e5da5Sopenharmony_ci  EXPECT_THAT(
131fd4e5da5Sopenharmony_ci      GetErrorMessage(),
132fd4e5da5Sopenharmony_ci      HasSubstr("Too many IDs (4294967296): combining all modules would "
133fd4e5da5Sopenharmony_ci                "overflow the 32-bit word of the SPIR-V header."));
134fd4e5da5Sopenharmony_ci}
135fd4e5da5Sopenharmony_ci
136fd4e5da5Sopenharmony_ci}  // namespace
137fd4e5da5Sopenharmony_ci}  // namespace spvtools
138