Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 1 | // Copyright (c) 2016 Google Inc. |
| 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 <memory> |
| 16 | #include <sstream> |
| 17 | #include <string> |
| 18 | #include <vector> |
| 19 | |
| 20 | #include "gmock/gmock.h" |
| 21 | #include "gtest/gtest.h" |
| 22 | #include "source/opt/build_module.h" |
| 23 | #include "source/opt/module.h" |
Ben Clayton | d552f63 | 2019-11-18 11:18:41 +0000 | [diff] [blame] | 24 | #include "source/opt/pass.h" |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 25 | #include "spirv-tools/libspirv.hpp" |
| 26 | #include "test/opt/module_utils.h" |
| 27 | |
| 28 | namespace spvtools { |
| 29 | namespace opt { |
| 30 | namespace { |
| 31 | |
| 32 | using ::testing::Eq; |
| 33 | using spvtest::GetIdBound; |
| 34 | |
| 35 | TEST(ModuleTest, SetIdBound) { |
| 36 | Module m; |
| 37 | // It's initialized to 0. |
| 38 | EXPECT_EQ(0u, GetIdBound(m)); |
| 39 | |
| 40 | m.SetIdBound(19); |
| 41 | EXPECT_EQ(19u, GetIdBound(m)); |
| 42 | |
| 43 | m.SetIdBound(102); |
| 44 | EXPECT_EQ(102u, GetIdBound(m)); |
| 45 | } |
| 46 | |
| 47 | // Returns an IRContext owning the module formed by assembling the given text, |
| 48 | // then loading the result. |
| 49 | inline std::unique_ptr<IRContext> BuildModule(std::string text) { |
| 50 | return spvtools::BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, |
| 51 | SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); |
| 52 | } |
| 53 | |
| 54 | TEST(ModuleTest, ComputeIdBound) { |
| 55 | // Emtpy module case. |
| 56 | EXPECT_EQ(1u, BuildModule("")->module()->ComputeIdBound()); |
| 57 | // Sensitive to result id |
| 58 | EXPECT_EQ(2u, BuildModule("%void = OpTypeVoid")->module()->ComputeIdBound()); |
| 59 | // Sensitive to type id |
| 60 | EXPECT_EQ(1000u, |
| 61 | BuildModule("%a = OpTypeArray !999 3")->module()->ComputeIdBound()); |
| 62 | // Sensitive to a regular Id parameter |
| 63 | EXPECT_EQ(2000u, |
| 64 | BuildModule("OpDecorate !1999 0")->module()->ComputeIdBound()); |
| 65 | // Sensitive to a scope Id parameter. |
| 66 | EXPECT_EQ(3000u, |
| 67 | BuildModule("%f = OpFunction %void None %fntype %a = OpLabel " |
| 68 | "OpMemoryBarrier !2999 %b\n") |
| 69 | ->module() |
| 70 | ->ComputeIdBound()); |
| 71 | // Sensitive to a semantics Id parameter |
| 72 | EXPECT_EQ(4000u, |
| 73 | BuildModule("%f = OpFunction %void None %fntype %a = OpLabel " |
| 74 | "OpMemoryBarrier %b !3999\n") |
| 75 | ->module() |
| 76 | ->ComputeIdBound()); |
| 77 | } |
| 78 | |
| 79 | TEST(ModuleTest, OstreamOperator) { |
| 80 | const std::string text = R"(OpCapability Shader |
| 81 | OpCapability Linkage |
| 82 | OpMemoryModel Logical GLSL450 |
| 83 | OpName %7 "restrict" |
| 84 | OpDecorate %8 Restrict |
| 85 | %9 = OpTypeVoid |
| 86 | %10 = OpTypeInt 32 0 |
| 87 | %11 = OpTypeStruct %10 %10 |
| 88 | %12 = OpTypePointer Function %10 |
| 89 | %13 = OpTypePointer Function %11 |
| 90 | %14 = OpConstant %10 0 |
| 91 | %15 = OpConstant %10 1 |
| 92 | %7 = OpTypeFunction %9 |
| 93 | %1 = OpFunction %9 None %7 |
| 94 | %2 = OpLabel |
| 95 | %8 = OpVariable %13 Function |
| 96 | %3 = OpAccessChain %12 %8 %14 |
| 97 | %4 = OpLoad %10 %3 |
| 98 | %5 = OpAccessChain %12 %8 %15 |
| 99 | %6 = OpLoad %10 %5 |
| 100 | OpReturn |
| 101 | OpFunctionEnd)"; |
| 102 | |
| 103 | std::string s; |
| 104 | std::ostringstream str(s); |
| 105 | str << *BuildModule(text)->module(); |
| 106 | EXPECT_EQ(text, str.str()); |
| 107 | } |
| 108 | |
| 109 | TEST(ModuleTest, OstreamOperatorInt64) { |
| 110 | const std::string text = R"(OpCapability Shader |
| 111 | OpCapability Linkage |
| 112 | OpCapability Int64 |
| 113 | OpMemoryModel Logical GLSL450 |
| 114 | OpName %7 "restrict" |
| 115 | OpDecorate %5 Restrict |
| 116 | %9 = OpTypeVoid |
| 117 | %10 = OpTypeInt 64 0 |
| 118 | %11 = OpTypeStruct %10 %10 |
| 119 | %12 = OpTypePointer Function %10 |
| 120 | %13 = OpTypePointer Function %11 |
| 121 | %14 = OpConstant %10 0 |
| 122 | %15 = OpConstant %10 1 |
| 123 | %16 = OpConstant %10 4294967297 |
| 124 | %7 = OpTypeFunction %9 |
| 125 | %1 = OpFunction %9 None %7 |
| 126 | %2 = OpLabel |
| 127 | %5 = OpVariable %12 Function |
| 128 | %6 = OpLoad %10 %5 |
| 129 | OpSelectionMerge %3 None |
| 130 | OpSwitch %6 %3 4294967297 %4 |
| 131 | %4 = OpLabel |
| 132 | OpBranch %3 |
| 133 | %3 = OpLabel |
| 134 | OpReturn |
| 135 | OpFunctionEnd)"; |
| 136 | |
| 137 | std::string s; |
| 138 | std::ostringstream str(s); |
| 139 | str << *BuildModule(text)->module(); |
| 140 | EXPECT_EQ(text, str.str()); |
| 141 | } |
| 142 | |
| 143 | TEST(ModuleTest, IdBoundTestAtLimit) { |
| 144 | const std::string text = R"( |
| 145 | OpCapability Shader |
| 146 | OpCapability Linkage |
| 147 | OpMemoryModel Logical GLSL450 |
| 148 | %1 = OpTypeVoid |
| 149 | %2 = OpTypeFunction %1 |
| 150 | %3 = OpFunction %1 None %2 |
| 151 | %4 = OpLabel |
| 152 | OpReturn |
| 153 | OpFunctionEnd)"; |
| 154 | |
| 155 | std::unique_ptr<IRContext> context = BuildModule(text); |
| 156 | uint32_t current_bound = context->module()->id_bound(); |
| 157 | context->set_max_id_bound(current_bound); |
| 158 | uint32_t next_id_bound = context->module()->TakeNextIdBound(); |
| 159 | EXPECT_EQ(next_id_bound, 0); |
| 160 | EXPECT_EQ(current_bound, context->module()->id_bound()); |
| 161 | next_id_bound = context->module()->TakeNextIdBound(); |
| 162 | EXPECT_EQ(next_id_bound, 0); |
| 163 | } |
| 164 | |
| 165 | TEST(ModuleTest, IdBoundTestBelowLimit) { |
| 166 | const std::string text = R"( |
| 167 | OpCapability Shader |
| 168 | OpCapability Linkage |
| 169 | OpMemoryModel Logical GLSL450 |
| 170 | %1 = OpTypeVoid |
| 171 | %2 = OpTypeFunction %1 |
| 172 | %3 = OpFunction %1 None %2 |
| 173 | %4 = OpLabel |
| 174 | OpReturn |
| 175 | OpFunctionEnd)"; |
| 176 | |
| 177 | std::unique_ptr<IRContext> context = BuildModule(text); |
| 178 | uint32_t current_bound = context->module()->id_bound(); |
| 179 | context->set_max_id_bound(current_bound + 100); |
| 180 | uint32_t next_id_bound = context->module()->TakeNextIdBound(); |
| 181 | EXPECT_EQ(next_id_bound, current_bound); |
| 182 | EXPECT_EQ(current_bound + 1, context->module()->id_bound()); |
| 183 | next_id_bound = context->module()->TakeNextIdBound(); |
| 184 | EXPECT_EQ(next_id_bound, current_bound + 1); |
| 185 | } |
| 186 | |
| 187 | TEST(ModuleTest, IdBoundTestNearLimit) { |
| 188 | const std::string text = R"( |
| 189 | OpCapability Shader |
| 190 | OpCapability Linkage |
| 191 | OpMemoryModel Logical GLSL450 |
| 192 | %1 = OpTypeVoid |
| 193 | %2 = OpTypeFunction %1 |
| 194 | %3 = OpFunction %1 None %2 |
| 195 | %4 = OpLabel |
| 196 | OpReturn |
| 197 | OpFunctionEnd)"; |
| 198 | |
| 199 | std::unique_ptr<IRContext> context = BuildModule(text); |
| 200 | uint32_t current_bound = context->module()->id_bound(); |
| 201 | context->set_max_id_bound(current_bound + 1); |
| 202 | uint32_t next_id_bound = context->module()->TakeNextIdBound(); |
| 203 | EXPECT_EQ(next_id_bound, current_bound); |
| 204 | EXPECT_EQ(current_bound + 1, context->module()->id_bound()); |
| 205 | next_id_bound = context->module()->TakeNextIdBound(); |
| 206 | EXPECT_EQ(next_id_bound, 0); |
| 207 | } |
| 208 | |
| 209 | TEST(ModuleTest, IdBoundTestUIntMax) { |
| 210 | const std::string text = R"( |
| 211 | OpCapability Shader |
| 212 | OpCapability Linkage |
| 213 | OpMemoryModel Logical GLSL450 |
| 214 | %1 = OpTypeVoid |
| 215 | %2 = OpTypeFunction %1 |
| 216 | %3 = OpFunction %1 None %2 |
| 217 | %4294967294 = OpLabel ; ID is UINT_MAX-1 |
| 218 | OpReturn |
| 219 | OpFunctionEnd)"; |
| 220 | |
| 221 | std::unique_ptr<IRContext> context = BuildModule(text); |
| 222 | uint32_t current_bound = context->module()->id_bound(); |
| 223 | |
| 224 | // Expecting |BuildModule| to preserve the numeric ids. |
| 225 | EXPECT_EQ(current_bound, std::numeric_limits<uint32_t>::max()); |
| 226 | |
| 227 | context->set_max_id_bound(current_bound); |
| 228 | uint32_t next_id_bound = context->module()->TakeNextIdBound(); |
| 229 | EXPECT_EQ(next_id_bound, 0); |
| 230 | EXPECT_EQ(current_bound, context->module()->id_bound()); |
| 231 | } |
Ben Clayton | d552f63 | 2019-11-18 11:18:41 +0000 | [diff] [blame] | 232 | |
| 233 | // Tests that "text" does not change when it is assembled, converted into a |
| 234 | // module, converted back to a binary, and then disassembled. |
| 235 | void AssembleAndDisassemble(const std::string& text) { |
| 236 | std::unique_ptr<IRContext> context = BuildModule(text); |
| 237 | std::vector<uint32_t> binary; |
| 238 | |
| 239 | context->module()->ToBinary(&binary, false); |
| 240 | |
| 241 | SpirvTools tools(SPV_ENV_UNIVERSAL_1_1); |
| 242 | std::string s; |
| 243 | tools.Disassemble(binary, &s); |
| 244 | EXPECT_EQ(s, text); |
| 245 | } |
| 246 | |
| 247 | TEST(ModuleTest, TrailingOpLine) { |
| 248 | const std::string text = R"(OpCapability Shader |
| 249 | OpCapability Linkage |
| 250 | OpMemoryModel Logical GLSL450 |
| 251 | %5 = OpString "file.ext" |
| 252 | %void = OpTypeVoid |
| 253 | %2 = OpTypeFunction %void |
| 254 | %3 = OpFunction %void None %2 |
| 255 | %4 = OpLabel |
| 256 | OpReturn |
| 257 | OpFunctionEnd |
| 258 | OpLine %5 1 0 |
| 259 | )"; |
| 260 | |
| 261 | AssembleAndDisassemble(text); |
| 262 | } |
| 263 | |
| 264 | TEST(ModuleTest, TrailingOpNoLine) { |
| 265 | const std::string text = R"(OpCapability Shader |
| 266 | OpCapability Linkage |
| 267 | OpMemoryModel Logical GLSL450 |
| 268 | %void = OpTypeVoid |
| 269 | %2 = OpTypeFunction %void |
| 270 | %3 = OpFunction %void None %2 |
| 271 | %4 = OpLabel |
| 272 | OpReturn |
| 273 | OpFunctionEnd |
| 274 | OpNoLine |
| 275 | )"; |
| 276 | |
| 277 | AssembleAndDisassemble(text); |
| 278 | } |
| 279 | |
| 280 | TEST(ModuleTest, MulitpleTrailingOpLine) { |
| 281 | const std::string text = R"(OpCapability Shader |
| 282 | OpCapability Linkage |
| 283 | OpMemoryModel Logical GLSL450 |
| 284 | %5 = OpString "file.ext" |
| 285 | %void = OpTypeVoid |
| 286 | %2 = OpTypeFunction %void |
| 287 | %3 = OpFunction %void None %2 |
| 288 | %4 = OpLabel |
| 289 | OpReturn |
| 290 | OpFunctionEnd |
| 291 | OpLine %5 1 0 |
| 292 | OpNoLine |
| 293 | OpLine %5 1 1 |
| 294 | )"; |
| 295 | |
| 296 | AssembleAndDisassemble(text); |
| 297 | } |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 298 | } // namespace |
| 299 | } // namespace opt |
| 300 | } // namespace spvtools |