Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 1 | // Copyright (c) 2019 Google LLC |
| 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 <array> |
| 16 | #include <sstream> |
| 17 | #include <string> |
| 18 | #include <vector> |
| 19 | |
| 20 | #include "gmock/gmock.h" |
| 21 | #include "pass_fixture.h" |
| 22 | #include "pass_utils.h" |
| 23 | #include "source/opt/graphics_robust_access_pass.h" |
| 24 | |
| 25 | namespace { |
| 26 | |
| 27 | using namespace spvtools; |
| 28 | |
| 29 | using opt::GraphicsRobustAccessPass; |
| 30 | using GraphicsRobustAccessTest = opt::PassTest<::testing::Test>; |
| 31 | |
| 32 | // Test incompatible module, determined at module-level. |
| 33 | |
| 34 | TEST_F(GraphicsRobustAccessTest, FailNotShader) { |
| 35 | const std::string text = R"( |
| 36 | ; CHECK: Can only process Shader modules |
| 37 | OpCapability Kernel |
| 38 | )"; |
| 39 | |
| 40 | SinglePassRunAndFail<GraphicsRobustAccessPass>(text); |
| 41 | } |
| 42 | |
| 43 | TEST_F(GraphicsRobustAccessTest, FailCantProcessVariablePointers) { |
| 44 | const std::string text = R"( |
| 45 | ; CHECK: Can't process modules with VariablePointers capability |
| 46 | OpCapability VariablePointers |
| 47 | )"; |
| 48 | |
| 49 | SinglePassRunAndFail<GraphicsRobustAccessPass>(text); |
| 50 | } |
| 51 | |
| 52 | TEST_F(GraphicsRobustAccessTest, FailCantProcessVariablePointersStorageBuffer) { |
| 53 | const std::string text = R"( |
| 54 | ; CHECK: Can't process modules with VariablePointersStorageBuffer capability |
| 55 | OpCapability VariablePointersStorageBuffer |
| 56 | )"; |
| 57 | |
| 58 | SinglePassRunAndFail<GraphicsRobustAccessPass>(text); |
| 59 | } |
| 60 | |
| 61 | TEST_F(GraphicsRobustAccessTest, FailCantProcessRuntimeDescriptorArrayEXT) { |
| 62 | const std::string text = R"( |
| 63 | ; CHECK: Can't process modules with RuntimeDescriptorArrayEXT capability |
| 64 | OpCapability RuntimeDescriptorArrayEXT |
| 65 | )"; |
| 66 | |
| 67 | SinglePassRunAndFail<GraphicsRobustAccessPass>(text); |
| 68 | } |
| 69 | |
| 70 | TEST_F(GraphicsRobustAccessTest, FailCantProcessPhysical32AddressingModel) { |
| 71 | const std::string text = R"( |
| 72 | ; CHECK: Addressing model must be Logical. Found OpMemoryModel Physical32 OpenCL |
| 73 | OpCapability Shader |
| 74 | OpMemoryModel Physical32 OpenCL |
| 75 | )"; |
| 76 | |
| 77 | SinglePassRunAndFail<GraphicsRobustAccessPass>(text); |
| 78 | } |
| 79 | |
| 80 | TEST_F(GraphicsRobustAccessTest, FailCantProcessPhysical64AddressingModel) { |
| 81 | const std::string text = R"( |
| 82 | ; CHECK: Addressing model must be Logical. Found OpMemoryModel Physical64 OpenCL |
| 83 | OpCapability Shader |
| 84 | OpMemoryModel Physical64 OpenCL |
| 85 | )"; |
| 86 | |
| 87 | SinglePassRunAndFail<GraphicsRobustAccessPass>(text); |
| 88 | } |
| 89 | |
| 90 | TEST_F(GraphicsRobustAccessTest, |
| 91 | FailCantProcessPhysicalStorageBuffer64EXTAddressingModel) { |
| 92 | const std::string text = R"( |
Ben Clayton | d552f63 | 2019-11-18 11:18:41 +0000 | [diff] [blame] | 93 | ; CHECK: Addressing model must be Logical. Found OpMemoryModel PhysicalStorageBuffer64 GLSL450 |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 94 | OpCapability Shader |
| 95 | OpMemoryModel PhysicalStorageBuffer64EXT GLSL450 |
| 96 | )"; |
| 97 | |
| 98 | SinglePassRunAndFail<GraphicsRobustAccessPass>(text); |
| 99 | } |
| 100 | |
| 101 | // Test access chains |
| 102 | |
| 103 | // Returns the names of access chain instructions handled by the pass. |
| 104 | // For the purposes of this pass, regular and in-bounds access chains are the |
| 105 | // same.) |
| 106 | std::vector<const char*> AccessChains() { |
| 107 | return {"OpAccessChain", "OpInBoundsAccessChain"}; |
| 108 | } |
| 109 | |
| 110 | std::string ShaderPreamble() { |
| 111 | return R"( |
| 112 | OpCapability Shader |
| 113 | OpMemoryModel Logical Simple |
| 114 | OpEntryPoint GLCompute %main "main" |
| 115 | )"; |
| 116 | } |
| 117 | |
| 118 | std::string ShaderPreamble(const std::vector<std::string>& names) { |
| 119 | std::ostringstream os; |
| 120 | os << ShaderPreamble(); |
| 121 | for (auto& name : names) { |
| 122 | os << " OpName %" << name << " \"" << name << "\"\n"; |
| 123 | } |
| 124 | return os.str(); |
| 125 | } |
| 126 | |
| 127 | std::string ShaderPreambleAC() { |
| 128 | return ShaderPreamble({"ac", "ptr_ty", "var"}); |
| 129 | } |
| 130 | |
| 131 | std::string ShaderPreambleAC(const std::vector<std::string>& names) { |
| 132 | auto names2 = names; |
| 133 | names2.push_back("ac"); |
| 134 | names2.push_back("ptr_ty"); |
| 135 | names2.push_back("var"); |
| 136 | return ShaderPreamble(names2); |
| 137 | } |
| 138 | |
| 139 | std::string DecoSSBO() { |
| 140 | return R"( |
| 141 | OpDecorate %ssbo_s BufferBlock |
| 142 | OpMemberDecorate %ssbo_s 0 Offset 0 |
| 143 | OpMemberDecorate %ssbo_s 1 Offset 4 |
| 144 | OpMemberDecorate %ssbo_s 2 Offset 16 |
| 145 | OpDecorate %var DescriptorSet 0 |
| 146 | OpDecorate %var Binding 0 |
| 147 | )"; |
| 148 | } |
| 149 | |
| 150 | std::string TypesVoid() { |
| 151 | return R"( |
| 152 | %void = OpTypeVoid |
| 153 | %void_fn = OpTypeFunction %void |
| 154 | )"; |
| 155 | } |
| 156 | |
| 157 | std::string TypesInt() { |
| 158 | return R"( |
| 159 | %uint = OpTypeInt 32 0 |
| 160 | %int = OpTypeInt 32 1 |
| 161 | )"; |
| 162 | } |
| 163 | |
| 164 | std::string TypesFloat() { |
| 165 | return R"( |
| 166 | %float = OpTypeFloat 32 |
| 167 | )"; |
| 168 | } |
| 169 | |
| 170 | std::string TypesShort() { |
| 171 | return R"( |
| 172 | %ushort = OpTypeInt 16 0 |
| 173 | %short = OpTypeInt 16 1 |
| 174 | )"; |
| 175 | } |
| 176 | |
| 177 | std::string TypesLong() { |
| 178 | return R"( |
| 179 | %ulong = OpTypeInt 64 0 |
| 180 | %long = OpTypeInt 64 1 |
| 181 | )"; |
| 182 | } |
| 183 | |
| 184 | std::string MainPrefix() { |
| 185 | return R"( |
| 186 | %main = OpFunction %void None %void_fn |
| 187 | %entry = OpLabel |
| 188 | )"; |
| 189 | } |
| 190 | |
| 191 | std::string MainSuffix() { |
| 192 | return R"( |
| 193 | OpReturn |
| 194 | OpFunctionEnd |
| 195 | )"; |
| 196 | } |
| 197 | |
| 198 | std::string ACCheck(const std::string& access_chain_inst, |
| 199 | const std::string& original, |
| 200 | const std::string& transformed) { |
| 201 | return "\n ; CHECK: %ac = " + access_chain_inst + " %ptr_ty %var" + |
Ben Clayton | d552f63 | 2019-11-18 11:18:41 +0000 | [diff] [blame] | 202 | (transformed.empty() ? "" : " ") + transformed + |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 203 | "\n ; CHECK-NOT: " + access_chain_inst + |
| 204 | "\n ; CHECK-NEXT: OpReturn" |
| 205 | "\n %ac = " + |
Ben Clayton | d552f63 | 2019-11-18 11:18:41 +0000 | [diff] [blame] | 206 | access_chain_inst + " %ptr_ty %var " + (original.empty() ? "" : " ") + |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 207 | original + "\n"; |
| 208 | } |
| 209 | |
| 210 | std::string ACCheckFail(const std::string& access_chain_inst, |
| 211 | const std::string& original, |
| 212 | const std::string& transformed) { |
| 213 | return "\n ; CHECK: %ac = " + access_chain_inst + " %ptr_ty %var" + |
Ben Clayton | d552f63 | 2019-11-18 11:18:41 +0000 | [diff] [blame] | 214 | (transformed.empty() ? "" : " ") + transformed + |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 215 | "\n ; CHECK-NOT: " + access_chain_inst + |
| 216 | "\n ; CHECK-NOT: OpReturn" |
| 217 | "\n %ac = " + |
Ben Clayton | d552f63 | 2019-11-18 11:18:41 +0000 | [diff] [blame] | 218 | access_chain_inst + " %ptr_ty %var " + (original.empty() ? "" : " ") + |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 219 | original + "\n"; |
| 220 | } |
| 221 | |
| 222 | // Access chain into: |
| 223 | // Vector |
| 224 | // Vector sizes 2, 3, 4 |
| 225 | // Matrix |
| 226 | // Matrix columns 2, 4 |
| 227 | // Component is vector 2, 4 |
| 228 | // Array |
| 229 | // Struct |
| 230 | // TODO(dneto): RuntimeArray |
| 231 | |
| 232 | TEST_F(GraphicsRobustAccessTest, ACVectorLeastInboundConstantUntouched) { |
| 233 | for (auto* ac : AccessChains()) { |
| 234 | std::ostringstream shaders; |
| 235 | shaders << ShaderPreambleAC() << TypesVoid() << TypesInt() << R"( |
| 236 | %uvec2 = OpTypeVector %uint 2 |
| 237 | %var_ty = OpTypePointer Function %uvec2 |
| 238 | %ptr_ty = OpTypePointer Function %uint |
| 239 | %uint_0 = OpConstant %uint 0 |
| 240 | )" |
| 241 | << MainPrefix() << R"( |
| 242 | %var = OpVariable %var_ty Function)" << ACCheck(ac, "%uint_0", "%uint_0") |
| 243 | << MainSuffix(); |
| 244 | SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true); |
| 245 | } |
| 246 | } |
| 247 | |
| 248 | TEST_F(GraphicsRobustAccessTest, ACVectorMostInboundConstantUntouched) { |
| 249 | for (auto* ac : AccessChains()) { |
| 250 | std::ostringstream shaders; |
| 251 | shaders << ShaderPreambleAC() << TypesVoid() << TypesInt() << R"( |
| 252 | %v4uint = OpTypeVector %uint 4 |
| 253 | %var_ty = OpTypePointer Function %v4uint |
| 254 | %ptr_ty = OpTypePointer Function %uint |
| 255 | %uint_3 = OpConstant %uint 3 |
| 256 | )" |
| 257 | << MainPrefix() << R"( |
| 258 | %var = OpVariable %var_ty Function)" << ACCheck(ac, "%uint_3", "%uint_3") |
| 259 | << MainSuffix(); |
| 260 | SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true); |
| 261 | } |
| 262 | } |
| 263 | |
| 264 | TEST_F(GraphicsRobustAccessTest, ACVectorExcessConstantClamped) { |
| 265 | for (auto* ac : AccessChains()) { |
| 266 | std::ostringstream shaders; |
| 267 | shaders << ShaderPreambleAC() << TypesVoid() << TypesInt() << R"( |
| 268 | %v4uint = OpTypeVector %uint 4 |
| 269 | %var_ty = OpTypePointer Function %v4uint |
| 270 | %ptr_ty = OpTypePointer Function %uint |
| 271 | %uint_4 = OpConstant %uint 4 |
| 272 | )" |
| 273 | << MainPrefix() << R"( |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 274 | %var = OpVariable %var_ty Function)" << ACCheck(ac, "%uint_4", "%int_3") |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 275 | << MainSuffix(); |
| 276 | SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true); |
| 277 | } |
| 278 | } |
| 279 | |
| 280 | TEST_F(GraphicsRobustAccessTest, ACVectorNegativeConstantClamped) { |
| 281 | for (auto* ac : AccessChains()) { |
| 282 | std::ostringstream shaders; |
| 283 | shaders << ShaderPreambleAC() << TypesVoid() << TypesInt() << R"( |
| 284 | %v4uint = OpTypeVector %uint 4 |
| 285 | %var_ty = OpTypePointer Function %v4uint |
| 286 | %ptr_ty = OpTypePointer Function %uint |
| 287 | %int_n1 = OpConstant %int -1 |
| 288 | )" |
| 289 | << MainPrefix() << R"( |
| 290 | ; CHECK: %int_0 = OpConstant %int 0 |
| 291 | %var = OpVariable %var_ty Function)" << ACCheck(ac, "%int_n1", "%int_0") |
| 292 | << MainSuffix(); |
| 293 | SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true); |
| 294 | } |
| 295 | } |
| 296 | |
| 297 | // Like the previous test, but ensures the pass knows how to modify an index |
| 298 | // which does not come first in the access chain. |
| 299 | TEST_F(GraphicsRobustAccessTest, ACVectorInArrayNegativeConstantClamped) { |
| 300 | for (auto* ac : AccessChains()) { |
| 301 | std::ostringstream shaders; |
| 302 | shaders << ShaderPreambleAC() << TypesVoid() << TypesInt() << R"( |
| 303 | %v4uint = OpTypeVector %uint 4 |
| 304 | %uint_1 = OpConstant %uint 1 |
| 305 | %uint_2 = OpConstant %uint 2 |
| 306 | %arr = OpTypeArray %v4uint %uint_2 |
| 307 | %var_ty = OpTypePointer Function %arr |
| 308 | %ptr_ty = OpTypePointer Function %uint |
| 309 | %int_n1 = OpConstant %int -1 |
| 310 | )" |
| 311 | << MainPrefix() << R"( |
| 312 | ; CHECK: %int_0 = OpConstant %int 0 |
| 313 | %var = OpVariable %var_ty Function)" |
| 314 | << ACCheck(ac, "%uint_1 %int_n1", "%uint_1 %int_0") << MainSuffix(); |
| 315 | SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true); |
| 316 | } |
| 317 | } |
| 318 | |
| 319 | TEST_F(GraphicsRobustAccessTest, ACVectorGeneralClamped) { |
| 320 | for (auto* ac : AccessChains()) { |
| 321 | std::ostringstream shaders; |
| 322 | shaders << ShaderPreambleAC({"i"}) << TypesVoid() << TypesInt() << R"( |
| 323 | %v4uint = OpTypeVector %uint 4 |
| 324 | %var_ty = OpTypePointer Function %v4uint |
| 325 | %ptr_ty = OpTypePointer Function %uint |
| 326 | %i = OpUndef %int)" |
| 327 | << MainPrefix() << R"( |
| 328 | ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" |
| 329 | ; CHECK-DAG: %int_0 = OpConstant %int 0 |
| 330 | ; CHECK-DAG: %int_3 = OpConstant %int 3 |
| 331 | ; CHECK: OpLabel |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 332 | ; CHECK: %[[clamp:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %i %int_0 %int_3 |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 333 | %var = OpVariable %var_ty Function)" << ACCheck(ac, "%i", "%[[clamp]]") |
| 334 | << MainSuffix(); |
| 335 | SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true); |
| 336 | } |
| 337 | } |
| 338 | |
| 339 | TEST_F(GraphicsRobustAccessTest, ACVectorGeneralShortClamped) { |
| 340 | // Show that signed 16 bit integers are clamped as well. |
| 341 | for (auto* ac : AccessChains()) { |
| 342 | std::ostringstream shaders; |
| 343 | shaders << "OpCapability Int16\n" |
| 344 | << ShaderPreambleAC({"i"}) << TypesVoid() << TypesShort() << |
| 345 | R"( |
| 346 | %v4short = OpTypeVector %short 4 |
| 347 | %var_ty = OpTypePointer Function %v4short |
| 348 | %ptr_ty = OpTypePointer Function %short |
| 349 | %i = OpUndef %short)" |
| 350 | << MainPrefix() << R"( |
| 351 | ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" |
| 352 | ; CHECK-NOT: = OpTypeInt 32 |
| 353 | ; CHECK-DAG: %short_0 = OpConstant %short 0 |
| 354 | ; CHECK-DAG: %short_3 = OpConstant %short 3 |
| 355 | ; CHECK-NOT: = OpTypeInt 32 |
| 356 | ; CHECK: OpLabel |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 357 | ; CHECK: %[[clamp:\w+]] = OpExtInst %short %[[GLSLSTD450]] SClamp %i %short_0 %short_3 |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 358 | %var = OpVariable %var_ty Function)" << ACCheck(ac, "%i", "%[[clamp]]") |
| 359 | << MainSuffix(); |
| 360 | SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true); |
| 361 | } |
| 362 | } |
| 363 | |
| 364 | TEST_F(GraphicsRobustAccessTest, ACVectorGeneralUShortClamped) { |
| 365 | // Show that unsigned 16 bit integers are clamped as well. |
| 366 | for (auto* ac : AccessChains()) { |
| 367 | std::ostringstream shaders; |
| 368 | shaders << "OpCapability Int16\n" |
| 369 | << ShaderPreambleAC({"i"}) << TypesVoid() << TypesShort() << |
| 370 | R"( |
| 371 | %v4ushort = OpTypeVector %ushort 4 |
| 372 | %var_ty = OpTypePointer Function %v4ushort |
| 373 | %ptr_ty = OpTypePointer Function %ushort |
| 374 | %i = OpUndef %ushort)" |
| 375 | << MainPrefix() << R"( |
| 376 | ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" |
| 377 | ; CHECK-NOT: = OpTypeInt 32 |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 378 | ; CHECK-DAG: %short_0 = OpConstant %short 0 |
| 379 | ; CHECK-DAG: %short_3 = OpConstant %short 3 |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 380 | ; CHECK-NOT: = OpTypeInt 32 |
| 381 | ; CHECK: OpLabel |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 382 | ; CHECK: %[[clamp:\w+]] = OpExtInst %ushort %[[GLSLSTD450]] SClamp %i %short_0 %short_3 |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 383 | %var = OpVariable %var_ty Function)" << ACCheck(ac, "%i", "%[[clamp]]") |
| 384 | << MainSuffix(); |
| 385 | SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true); |
| 386 | } |
| 387 | } |
| 388 | |
| 389 | TEST_F(GraphicsRobustAccessTest, ACVectorGeneralLongClamped) { |
| 390 | // Show that signed 64 bit integers are clamped as well. |
| 391 | for (auto* ac : AccessChains()) { |
| 392 | std::ostringstream shaders; |
| 393 | shaders << "OpCapability Int64\n" |
| 394 | << ShaderPreambleAC({"i"}) << TypesVoid() << TypesLong() << |
| 395 | R"( |
| 396 | %v4long = OpTypeVector %long 4 |
| 397 | %var_ty = OpTypePointer Function %v4long |
| 398 | %ptr_ty = OpTypePointer Function %long |
| 399 | %i = OpUndef %long)" |
| 400 | << MainPrefix() << R"( |
| 401 | ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" |
| 402 | ; CHECK-NOT: = OpTypeInt 32 |
| 403 | ; CHECK-DAG: %long_0 = OpConstant %long 0 |
| 404 | ; CHECK-DAG: %long_3 = OpConstant %long 3 |
| 405 | ; CHECK-NOT: = OpTypeInt 32 |
| 406 | ; CHECK: OpLabel |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 407 | ; CHECK: %[[clamp:\w+]] = OpExtInst %long %[[GLSLSTD450]] SClamp %i %long_0 %long_3 |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 408 | %var = OpVariable %var_ty Function)" << ACCheck(ac, "%i", "%[[clamp]]") |
| 409 | << MainSuffix(); |
| 410 | SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true); |
| 411 | } |
| 412 | } |
| 413 | |
| 414 | TEST_F(GraphicsRobustAccessTest, ACVectorGeneralULongClamped) { |
| 415 | // Show that unsigned 64 bit integers are clamped as well. |
| 416 | for (auto* ac : AccessChains()) { |
| 417 | std::ostringstream shaders; |
| 418 | shaders << "OpCapability Int64\n" |
| 419 | << ShaderPreambleAC({"i"}) << TypesVoid() << TypesLong() << |
| 420 | R"( |
| 421 | %v4ulong = OpTypeVector %ulong 4 |
| 422 | %var_ty = OpTypePointer Function %v4ulong |
| 423 | %ptr_ty = OpTypePointer Function %ulong |
| 424 | %i = OpUndef %ulong)" |
| 425 | << MainPrefix() << R"( |
| 426 | ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" |
| 427 | ; CHECK-NOT: = OpTypeInt 32 |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 428 | ; CHECK-DAG: %long_0 = OpConstant %long 0 |
| 429 | ; CHECK-DAG: %long_3 = OpConstant %long 3 |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 430 | ; CHECK-NOT: = OpTypeInt 32 |
| 431 | ; CHECK: OpLabel |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 432 | ; CHECK: %[[clamp:\w+]] = OpExtInst %ulong %[[GLSLSTD450]] SClamp %i %long_0 %long_3 |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 433 | %var = OpVariable %var_ty Function)" << ACCheck(ac, "%i", "%[[clamp]]") |
| 434 | << MainSuffix(); |
| 435 | SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true); |
| 436 | } |
| 437 | } |
| 438 | |
| 439 | TEST_F(GraphicsRobustAccessTest, ACMatrixLeastInboundConstantUntouched) { |
| 440 | for (auto* ac : AccessChains()) { |
| 441 | std::ostringstream shaders; |
| 442 | shaders << ShaderPreambleAC() << TypesVoid() << TypesInt() |
| 443 | << TypesFloat() << R"( |
| 444 | %v2float = OpTypeVector %float 2 |
| 445 | %mat4v2float = OpTypeMatrix %v2float 4 |
| 446 | %var_ty = OpTypePointer Function %mat4v2float |
| 447 | %ptr_ty = OpTypePointer Function %float |
| 448 | %uint_0 = OpConstant %uint 0 |
| 449 | %uint_1 = OpConstant %uint 1 |
| 450 | )" << MainPrefix() << R"( |
| 451 | %var = OpVariable %var_ty Function)" |
| 452 | << ACCheck(ac, "%uint_0 %uint_1", "%uint_0 %uint_1") |
| 453 | << MainSuffix(); |
| 454 | SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true); |
| 455 | } |
| 456 | } |
| 457 | |
| 458 | TEST_F(GraphicsRobustAccessTest, ACMatrixMostInboundConstantUntouched) { |
| 459 | for (auto* ac : AccessChains()) { |
| 460 | std::ostringstream shaders; |
| 461 | shaders << ShaderPreambleAC() << TypesVoid() << TypesInt() |
| 462 | << TypesFloat() << R"( |
| 463 | %v2float = OpTypeVector %float 2 |
| 464 | %mat4v2float = OpTypeMatrix %v2float 4 |
| 465 | %var_ty = OpTypePointer Function %mat4v2float |
| 466 | %ptr_ty = OpTypePointer Function %float |
| 467 | %uint_1 = OpConstant %uint 1 |
| 468 | %uint_3 = OpConstant %uint 3 |
| 469 | )" << MainPrefix() << R"( |
| 470 | %var = OpVariable %var_ty Function)" |
| 471 | << ACCheck(ac, "%uint_3 %uint_1", "%uint_3 %uint_1") |
| 472 | << MainSuffix(); |
| 473 | SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true); |
| 474 | } |
| 475 | } |
| 476 | |
| 477 | TEST_F(GraphicsRobustAccessTest, ACMatrixExcessConstantClamped) { |
| 478 | for (auto* ac : AccessChains()) { |
| 479 | std::ostringstream shaders; |
| 480 | shaders << ShaderPreambleAC() << TypesVoid() << TypesInt() |
| 481 | << TypesFloat() << R"( |
| 482 | %v2float = OpTypeVector %float 2 |
| 483 | %mat4v2float = OpTypeMatrix %v2float 4 |
| 484 | %var_ty = OpTypePointer Function %mat4v2float |
| 485 | %ptr_ty = OpTypePointer Function %float |
| 486 | %uint_1 = OpConstant %uint 1 |
| 487 | %uint_4 = OpConstant %uint 4 |
| 488 | )" << MainPrefix() << R"( |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 489 | ; CHECK: %int_3 = OpConstant %int 3 |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 490 | %var = OpVariable %var_ty Function)" |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 491 | << ACCheck(ac, "%uint_4 %uint_1", "%int_3 %uint_1") << MainSuffix(); |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 492 | SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true); |
| 493 | } |
| 494 | } |
| 495 | |
| 496 | TEST_F(GraphicsRobustAccessTest, ACMatrixNegativeConstantClamped) { |
| 497 | for (auto* ac : AccessChains()) { |
| 498 | std::ostringstream shaders; |
| 499 | shaders << ShaderPreambleAC() << TypesVoid() << TypesInt() |
| 500 | << TypesFloat() << R"( |
| 501 | %v2float = OpTypeVector %float 2 |
| 502 | %mat4v2float = OpTypeMatrix %v2float 4 |
| 503 | %var_ty = OpTypePointer Function %mat4v2float |
| 504 | %ptr_ty = OpTypePointer Function %float |
| 505 | %uint_1 = OpConstant %uint 1 |
| 506 | %int_n1 = OpConstant %int -1 |
| 507 | )" << MainPrefix() << R"( |
| 508 | ; CHECK: %int_0 = OpConstant %int 0 |
| 509 | %var = OpVariable %var_ty Function)" |
| 510 | << ACCheck(ac, "%int_n1 %uint_1", "%int_0 %uint_1") << MainSuffix(); |
| 511 | SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true); |
| 512 | } |
| 513 | } |
| 514 | |
| 515 | TEST_F(GraphicsRobustAccessTest, ACMatrixGeneralClamped) { |
| 516 | for (auto* ac : AccessChains()) { |
| 517 | std::ostringstream shaders; |
| 518 | shaders << ShaderPreambleAC({"i"}) << TypesVoid() << TypesInt() |
| 519 | << TypesFloat() << R"( |
| 520 | %v2float = OpTypeVector %float 2 |
| 521 | %mat4v2float = OpTypeMatrix %v2float 4 |
| 522 | %var_ty = OpTypePointer Function %mat4v2float |
| 523 | %ptr_ty = OpTypePointer Function %float |
| 524 | %uint_1 = OpConstant %uint 1 |
| 525 | %i = OpUndef %int |
| 526 | )" << MainPrefix() << R"( |
| 527 | ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" |
| 528 | ; CHECK-DAG: %int_0 = OpConstant %int 0 |
| 529 | ; CHECK-DAG: %int_3 = OpConstant %int 3 |
| 530 | ; CHECK: OpLabel |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 531 | ; CHECK: %[[clamp:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %i %int_0 %int_3 |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 532 | %var = OpVariable %var_ty Function)" |
| 533 | << ACCheck(ac, "%i %uint_1", "%[[clamp]] %uint_1") << MainSuffix(); |
| 534 | SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true); |
| 535 | } |
| 536 | } |
| 537 | |
| 538 | TEST_F(GraphicsRobustAccessTest, ACArrayLeastInboundConstantUntouched) { |
| 539 | for (auto* ac : AccessChains()) { |
| 540 | std::ostringstream shaders; |
| 541 | shaders << ShaderPreambleAC() << TypesVoid() << TypesInt() |
| 542 | << TypesFloat() << R"( |
| 543 | %uint_200 = OpConstant %uint 200 |
| 544 | %arr = OpTypeArray %float %uint_200 |
| 545 | %var_ty = OpTypePointer Function %arr |
| 546 | %ptr_ty = OpTypePointer Function %float |
| 547 | %int_0 = OpConstant %int 0 |
| 548 | )" << MainPrefix() << R"( |
| 549 | %var = OpVariable %var_ty Function)" |
| 550 | << ACCheck(ac, "%int_0", "%int_0") << MainSuffix(); |
| 551 | SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true); |
| 552 | } |
| 553 | } |
| 554 | |
| 555 | TEST_F(GraphicsRobustAccessTest, ACArrayMostInboundConstantUntouched) { |
| 556 | for (auto* ac : AccessChains()) { |
| 557 | std::ostringstream shaders; |
| 558 | shaders << ShaderPreambleAC() << TypesVoid() << TypesInt() |
| 559 | << TypesFloat() << R"( |
| 560 | %uint_200 = OpConstant %uint 200 |
| 561 | %arr = OpTypeArray %float %uint_200 |
| 562 | %var_ty = OpTypePointer Function %arr |
| 563 | %ptr_ty = OpTypePointer Function %float |
| 564 | %int_199 = OpConstant %int 199 |
| 565 | )" << MainPrefix() << R"( |
| 566 | %var = OpVariable %var_ty Function)" |
| 567 | << ACCheck(ac, "%int_199", "%int_199") << MainSuffix(); |
| 568 | SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true); |
| 569 | } |
| 570 | } |
| 571 | |
| 572 | TEST_F(GraphicsRobustAccessTest, ACArrayGeneralClamped) { |
| 573 | for (auto* ac : AccessChains()) { |
| 574 | std::ostringstream shaders; |
| 575 | shaders << ShaderPreambleAC({"i"}) << TypesVoid() << TypesInt() |
| 576 | << TypesFloat() << R"( |
| 577 | %uint_200 = OpConstant %uint 200 |
| 578 | %arr = OpTypeArray %float %uint_200 |
| 579 | %var_ty = OpTypePointer Function %arr |
| 580 | %ptr_ty = OpTypePointer Function %float |
| 581 | %i = OpUndef %int |
| 582 | )" << MainPrefix() << R"( |
| 583 | ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" |
| 584 | ; CHECK-DAG: %int_0 = OpConstant %int 0 |
| 585 | ; CHECK-DAG: %int_199 = OpConstant %int 199 |
| 586 | ; CHECK: OpLabel |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 587 | ; CHECK: %[[clamp:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %i %int_0 %int_199 |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 588 | %var = OpVariable %var_ty Function)" |
| 589 | << ACCheck(ac, "%i", "%[[clamp]]") << MainSuffix(); |
| 590 | SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true); |
| 591 | } |
| 592 | } |
| 593 | |
| 594 | TEST_F(GraphicsRobustAccessTest, ACArrayGeneralShortIndexUIntBoundsClamped) { |
| 595 | // Index is signed short, array bounds overflows the index type. |
| 596 | for (auto* ac : AccessChains()) { |
| 597 | std::ostringstream shaders; |
| 598 | shaders << "OpCapability Int16\n" |
| 599 | << ShaderPreambleAC({"i"}) << TypesVoid() << TypesInt() |
| 600 | << TypesShort() << TypesFloat() << R"( |
| 601 | %uint_70000 = OpConstant %uint 70000 ; overflows 16bits |
| 602 | %arr = OpTypeArray %float %uint_70000 |
| 603 | %var_ty = OpTypePointer Function %arr |
| 604 | %ptr_ty = OpTypePointer Function %float |
| 605 | %i = OpUndef %short |
| 606 | )" << MainPrefix() << R"( |
| 607 | ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 608 | ; CHECK-DAG: %int_0 = OpConstant %int 0 |
| 609 | ; CHECK-DAG: %int_69999 = OpConstant %int 69999 |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 610 | ; CHECK: OpLabel |
| 611 | ; CHECK: %[[i_ext:\w+]] = OpSConvert %uint %i |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 612 | ; CHECK: %[[clamp:\w+]] = OpExtInst %uint %[[GLSLSTD450]] SClamp %[[i_ext]] %int_0 %int_69999 |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 613 | %var = OpVariable %var_ty Function)" |
| 614 | << ACCheck(ac, "%i", "%[[clamp]]") << MainSuffix(); |
| 615 | SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true); |
| 616 | } |
| 617 | } |
| 618 | |
| 619 | TEST_F(GraphicsRobustAccessTest, ACArrayGeneralUShortIndexIntBoundsClamped) { |
| 620 | // Index is unsigned short, array bounds overflows the index type. |
| 621 | for (auto* ac : AccessChains()) { |
| 622 | std::ostringstream shaders; |
| 623 | shaders << "OpCapability Int16\n" |
| 624 | << ShaderPreambleAC({"i"}) << TypesVoid() << TypesInt() |
| 625 | << TypesShort() << TypesFloat() << R"( |
| 626 | %int_70000 = OpConstant %int 70000 ; overflows 16bits |
| 627 | %arr = OpTypeArray %float %int_70000 |
| 628 | %var_ty = OpTypePointer Function %arr |
| 629 | %ptr_ty = OpTypePointer Function %float |
| 630 | %i = OpUndef %ushort |
| 631 | )" << MainPrefix() << R"( |
| 632 | ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 633 | ; CHECK-DAG: %int_0 = OpConstant %int 0 |
| 634 | ; CHECK-DAG: %int_69999 = OpConstant %int 69999 |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 635 | ; CHECK: OpLabel |
| 636 | ; CHECK: %[[i_ext:\w+]] = OpUConvert %uint %i |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 637 | ; CHECK: %[[clamp:\w+]] = OpExtInst %uint %[[GLSLSTD450]] SClamp %[[i_ext]] %int_0 %int_69999 |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 638 | %var = OpVariable %var_ty Function)" |
| 639 | << ACCheck(ac, "%i", "%[[clamp]]") << MainSuffix(); |
| 640 | SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true); |
| 641 | } |
| 642 | } |
| 643 | |
| 644 | TEST_F(GraphicsRobustAccessTest, ACArrayGeneralUIntIndexShortBoundsClamped) { |
| 645 | // Signed int index i is wider than the array bounds type. |
| 646 | for (auto* ac : AccessChains()) { |
| 647 | std::ostringstream shaders; |
| 648 | shaders << "OpCapability Int16\n" |
| 649 | << ShaderPreambleAC({"i"}) << TypesVoid() << TypesInt() |
| 650 | << TypesShort() << TypesFloat() << R"( |
| 651 | %short_200 = OpConstant %short 200 |
| 652 | %arr = OpTypeArray %float %short_200 |
| 653 | %var_ty = OpTypePointer Function %arr |
| 654 | %ptr_ty = OpTypePointer Function %float |
| 655 | %i = OpUndef %uint |
| 656 | )" << MainPrefix() << R"( |
| 657 | ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 658 | ; CHECK-DAG: %int_0 = OpConstant %int 0 |
| 659 | ; CHECK-DAG: %int_199 = OpConstant %int 199 |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 660 | ; CHECK: OpLabel |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 661 | ; CHECK: %[[clamp:\w+]] = OpExtInst %uint %[[GLSLSTD450]] SClamp %i %int_0 %int_199 |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 662 | %var = OpVariable %var_ty Function)" |
| 663 | << ACCheck(ac, "%i", "%[[clamp]]") << MainSuffix(); |
| 664 | SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true); |
| 665 | } |
| 666 | } |
| 667 | |
| 668 | TEST_F(GraphicsRobustAccessTest, ACArrayGeneralIntIndexUShortBoundsClamped) { |
| 669 | // Unsigned int index i is wider than the array bounds type. |
| 670 | for (auto* ac : AccessChains()) { |
| 671 | std::ostringstream shaders; |
| 672 | shaders << "OpCapability Int16\n" |
| 673 | << ShaderPreambleAC({"i"}) << TypesVoid() << TypesInt() |
| 674 | << TypesShort() << TypesFloat() << R"( |
| 675 | %ushort_200 = OpConstant %ushort 200 |
| 676 | %arr = OpTypeArray %float %ushort_200 |
| 677 | %var_ty = OpTypePointer Function %arr |
| 678 | %ptr_ty = OpTypePointer Function %float |
| 679 | %i = OpUndef %int |
| 680 | )" << MainPrefix() << R"( |
| 681 | ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" |
| 682 | ; CHECK-DAG: %int_0 = OpConstant %int 0 |
| 683 | ; CHECK-DAG: %int_199 = OpConstant %int 199 |
| 684 | ; CHECK: OpLabel |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 685 | ; CHECK: %[[clamp:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %i %int_0 %int_199 |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 686 | %var = OpVariable %var_ty Function)" |
| 687 | << ACCheck(ac, "%i", "%[[clamp]]") << MainSuffix(); |
| 688 | SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true); |
| 689 | } |
| 690 | } |
| 691 | |
| 692 | TEST_F(GraphicsRobustAccessTest, ACArrayGeneralLongIndexUIntBoundsClamped) { |
| 693 | // Signed long index i is wider than the array bounds type. |
| 694 | for (auto* ac : AccessChains()) { |
| 695 | std::ostringstream shaders; |
| 696 | shaders << "OpCapability Int64\n" |
| 697 | << ShaderPreambleAC({"i"}) << TypesVoid() << TypesInt() |
| 698 | << TypesLong() << TypesFloat() << R"( |
| 699 | %uint_200 = OpConstant %uint 200 |
| 700 | %arr = OpTypeArray %float %uint_200 |
| 701 | %var_ty = OpTypePointer Function %arr |
| 702 | %ptr_ty = OpTypePointer Function %float |
| 703 | %i = OpUndef %long |
| 704 | )" << MainPrefix() << R"( |
| 705 | ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" |
| 706 | ; CHECK-DAG: %long_0 = OpConstant %long 0 |
| 707 | ; CHECK-DAG: %long_199 = OpConstant %long 199 |
| 708 | ; CHECK: OpLabel |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 709 | ; CHECK: %[[clamp:\w+]] = OpExtInst %long %[[GLSLSTD450]] SClamp %i %long_0 %long_199 |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 710 | %var = OpVariable %var_ty Function)" |
| 711 | << ACCheck(ac, "%i", "%[[clamp]]") << MainSuffix(); |
| 712 | SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true); |
| 713 | } |
| 714 | } |
| 715 | |
| 716 | TEST_F(GraphicsRobustAccessTest, ACArrayGeneralULongIndexIntBoundsClamped) { |
| 717 | // Unsigned long index i is wider than the array bounds type. |
| 718 | for (auto* ac : AccessChains()) { |
| 719 | std::ostringstream shaders; |
| 720 | shaders << "OpCapability Int64\n" |
| 721 | << ShaderPreambleAC({"i"}) << TypesVoid() << TypesInt() |
| 722 | << TypesLong() << TypesFloat() << R"( |
| 723 | %int_200 = OpConstant %int 200 |
| 724 | %arr = OpTypeArray %float %int_200 |
| 725 | %var_ty = OpTypePointer Function %arr |
| 726 | %ptr_ty = OpTypePointer Function %float |
| 727 | %i = OpUndef %ulong |
| 728 | )" << MainPrefix() << R"( |
| 729 | ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 730 | ; CHECK-DAG: %long_0 = OpConstant %long 0 |
| 731 | ; CHECK-DAG: %long_199 = OpConstant %long 199 |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 732 | ; CHECK: OpLabel |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 733 | ; CHECK: %[[clamp:\w+]] = OpExtInst %ulong %[[GLSLSTD450]] SClamp %i %long_0 %long_199 |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 734 | %var = OpVariable %var_ty Function)" |
| 735 | << ACCheck(ac, "%i", "%[[clamp]]") << MainSuffix(); |
| 736 | SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true); |
| 737 | } |
| 738 | } |
| 739 | |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 740 | TEST_F(GraphicsRobustAccessTest, |
| 741 | ACArrayGeneralShortIndeArrayBiggerThanShortMaxClipsToShortIntMax) { |
| 742 | for (auto* ac : AccessChains()) { |
| 743 | std::ostringstream shaders; |
| 744 | shaders << "OpCapability Int16\n" |
| 745 | << ShaderPreambleAC({"i"}) << TypesVoid() << TypesShort() |
| 746 | << TypesInt() << TypesFloat() << R"( |
| 747 | %uint_50000 = OpConstant %uint 50000 |
| 748 | %arr = OpTypeArray %float %uint_50000 |
| 749 | %var_ty = OpTypePointer Function %arr |
| 750 | %ptr_ty = OpTypePointer Function %float |
| 751 | %i = OpUndef %ushort |
| 752 | )" << MainPrefix() << R"( |
| 753 | ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" |
| 754 | ; CHECK-DAG: %short_0 = OpConstant %short 0 |
| 755 | ; CHECK-DAG: %[[intmax:\w+]] = OpConstant %short 32767 |
| 756 | ; CHECK: OpLabel |
| 757 | ; CHECK: %[[clamp:\w+]] = OpExtInst %ushort %[[GLSLSTD450]] SClamp %i %short_0 %[[intmax]] |
| 758 | %var = OpVariable %var_ty Function)" |
| 759 | << ACCheck(ac, "%i", "%[[clamp]]") << MainSuffix(); |
| 760 | SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true); |
| 761 | } |
| 762 | } |
| 763 | |
| 764 | TEST_F(GraphicsRobustAccessTest, |
| 765 | ACArrayGeneralIntIndexArrayBiggerThanIntMaxClipsToSignedIntMax) { |
| 766 | for (auto* ac : AccessChains()) { |
| 767 | std::ostringstream shaders; |
| 768 | shaders << ShaderPreambleAC({"i"}) << TypesVoid() << TypesInt() |
| 769 | << TypesFloat() << R"( |
| 770 | %uint_3000000000 = OpConstant %uint 3000000000 |
| 771 | %arr = OpTypeArray %float %uint_3000000000 |
| 772 | %var_ty = OpTypePointer Function %arr |
| 773 | %ptr_ty = OpTypePointer Function %float |
| 774 | %i = OpUndef %uint |
| 775 | )" << MainPrefix() << R"( |
| 776 | ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" |
| 777 | ; CHECK-DAG: %int_0 = OpConstant %int 0 |
| 778 | ; CHECK-DAG: %[[intmax:\w+]] = OpConstant %int 2147483647 |
| 779 | ; CHECK: OpLabel |
| 780 | ; CHECK: %[[clamp:\w+]] = OpExtInst %uint %[[GLSLSTD450]] SClamp %i %int_0 %[[intmax]] |
| 781 | %var = OpVariable %var_ty Function)" |
| 782 | << ACCheck(ac, "%i", "%[[clamp]]") << MainSuffix(); |
| 783 | SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true); |
| 784 | } |
| 785 | } |
| 786 | |
| 787 | TEST_F(GraphicsRobustAccessTest, |
| 788 | ACArrayGeneralLongIndexArrayBiggerThanLongMaxClipsToSignedLongMax) { |
| 789 | for (auto* ac : AccessChains()) { |
| 790 | std::ostringstream shaders; |
| 791 | shaders << "OpCapability Int64\n" |
| 792 | << ShaderPreambleAC({"i"}) << TypesVoid() << TypesInt() |
| 793 | << TypesLong() |
| 794 | << TypesFloat() |
| 795 | // 2^63 == 9,223,372,036,854,775,807 |
| 796 | << R"( |
| 797 | %ulong_9223372036854775999 = OpConstant %ulong 9223372036854775999 |
| 798 | %arr = OpTypeArray %float %ulong_9223372036854775999 |
| 799 | %var_ty = OpTypePointer Function %arr |
| 800 | %ptr_ty = OpTypePointer Function %float |
| 801 | %i = OpUndef %ulong |
| 802 | )" |
| 803 | << MainPrefix() << R"( |
| 804 | ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" |
| 805 | ; CHECK-DAG: %long_0 = OpConstant %long 0 |
| 806 | ; CHECK-DAG: %[[intmax:\w+]] = OpConstant %long 9223372036854775807 |
| 807 | ; CHECK: OpLabel |
| 808 | ; CHECK: %[[clamp:\w+]] = OpExtInst %ulong %[[GLSLSTD450]] SClamp %i %long_0 %[[intmax]] |
| 809 | %var = OpVariable %var_ty Function)" << ACCheck(ac, "%i", "%[[clamp]]") |
| 810 | << MainSuffix(); |
| 811 | SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true); |
| 812 | } |
| 813 | } |
| 814 | |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 815 | TEST_F(GraphicsRobustAccessTest, ACArraySpecIdSizedAlwaysClamped) { |
| 816 | for (auto* ac : AccessChains()) { |
| 817 | std::ostringstream shaders; |
| 818 | shaders << ShaderPreambleAC({"spec200"}) << R"( |
| 819 | OpDecorate %spec200 SpecId 0 )" << TypesVoid() << TypesInt() |
| 820 | << TypesFloat() << R"( |
| 821 | %spec200 = OpSpecConstant %int 200 |
| 822 | %arr = OpTypeArray %float %spec200 |
| 823 | %var_ty = OpTypePointer Function %arr |
| 824 | %ptr_ty = OpTypePointer Function %float |
| 825 | %uint_5 = OpConstant %uint 5 |
| 826 | )" << MainPrefix() << R"( |
| 827 | ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" |
| 828 | ; CHECK-DAG: %uint_0 = OpConstant %uint 0 |
| 829 | ; CHECK-DAG: %uint_1 = OpConstant %uint 1 |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 830 | ; CHECK-DAG: %[[uint_intmax:\w+]] = OpConstant %uint 2147483647 |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 831 | ; CHECK: OpLabel |
| 832 | ; CHECK: %[[max:\w+]] = OpISub %uint %spec200 %uint_1 |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 833 | ; CHECK: %[[smin:\w+]] = OpExtInst %uint %[[GLSLSTD450]] UMin %[[max]] %[[uint_intmax]] |
| 834 | ; CHECK: %[[clamp:\w+]] = OpExtInst %uint %[[GLSLSTD450]] SClamp %uint_5 %uint_0 %[[smin]] |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 835 | %var = OpVariable %var_ty Function)" |
| 836 | << ACCheck(ac, "%uint_5", "%[[clamp]]") << MainSuffix(); |
| 837 | SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true); |
| 838 | } |
| 839 | } |
| 840 | |
| 841 | TEST_F(GraphicsRobustAccessTest, ACStructLeastUntouched) { |
| 842 | for (auto* ac : AccessChains()) { |
| 843 | std::ostringstream shaders; |
| 844 | shaders << ShaderPreambleAC() << TypesVoid() << TypesInt() |
| 845 | << TypesFloat() << R"( |
| 846 | %struct = OpTypeStruct %float %float %float |
| 847 | %var_ty = OpTypePointer Function %struct |
| 848 | %ptr_ty = OpTypePointer Function %float |
| 849 | %int_0 = OpConstant %int 0 |
| 850 | )" << MainPrefix() << R"( |
| 851 | %var = OpVariable %var_ty Function)" |
| 852 | << ACCheck(ac, "%int_0", "%int_0") << MainSuffix(); |
| 853 | SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true); |
| 854 | } |
| 855 | } |
| 856 | |
| 857 | TEST_F(GraphicsRobustAccessTest, ACStructMostUntouched) { |
| 858 | for (auto* ac : AccessChains()) { |
| 859 | std::ostringstream shaders; |
| 860 | shaders << ShaderPreambleAC() << TypesVoid() << TypesInt() |
| 861 | << TypesFloat() << R"( |
| 862 | %struct = OpTypeStruct %float %float %float |
| 863 | %var_ty = OpTypePointer Function %struct |
| 864 | %ptr_ty = OpTypePointer Function %float |
| 865 | %int_2 = OpConstant %int 2 |
| 866 | )" << MainPrefix() << R"( |
| 867 | %var = OpVariable %var_ty Function)" |
| 868 | << ACCheck(ac, "%int_2", "%int_2") << MainSuffix(); |
| 869 | SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true); |
| 870 | } |
| 871 | } |
| 872 | |
| 873 | TEST_F(GraphicsRobustAccessTest, ACStructSpecConstantFail) { |
| 874 | for (auto* ac : AccessChains()) { |
| 875 | std::ostringstream shaders; |
| 876 | shaders << ShaderPreambleAC({"struct", "spec200"}) |
| 877 | << "OpDecorate %spec200 SpecId 0\n" |
| 878 | << |
| 879 | |
| 880 | TypesVoid() << TypesInt() << TypesFloat() << R"( |
| 881 | %spec200 = OpSpecConstant %int 200 |
| 882 | %struct = OpTypeStruct %float %float %float |
| 883 | %var_ty = OpTypePointer Function %struct |
| 884 | %ptr_ty = OpTypePointer Function %float |
| 885 | )" << MainPrefix() << R"( |
| 886 | %var = OpVariable %var_ty Function |
| 887 | ; CHECK: Member index into struct is not a constant integer |
| 888 | ; CHECK-SAME: %spec200 = OpSpecConstant %int 200 |
| 889 | )" |
| 890 | << ACCheckFail(ac, "%spec200", "%spec200") << MainSuffix(); |
| 891 | SinglePassRunAndFail<GraphicsRobustAccessPass>(shaders.str()); |
| 892 | } |
| 893 | } |
| 894 | |
| 895 | TEST_F(GraphicsRobustAccessTest, ACStructFloatConstantFail) { |
| 896 | for (auto* ac : AccessChains()) { |
| 897 | std::ostringstream shaders; |
| 898 | shaders << ShaderPreambleAC({"struct"}) << |
| 899 | |
| 900 | TypesVoid() << TypesInt() << TypesFloat() << R"( |
| 901 | %float_2 = OpConstant %float 2 |
| 902 | %struct = OpTypeStruct %float %float %float |
| 903 | %var_ty = OpTypePointer Function %struct |
| 904 | %ptr_ty = OpTypePointer Function %float |
| 905 | )" << MainPrefix() << R"( |
| 906 | %var = OpVariable %var_ty Function |
| 907 | ; CHECK: Member index into struct is not a constant integer |
| 908 | ; CHECK-SAME: %float_2 = OpConstant %float 2 |
| 909 | )" |
| 910 | << ACCheckFail(ac, "%float_2", "%float_2") << MainSuffix(); |
| 911 | SinglePassRunAndFail<GraphicsRobustAccessPass>(shaders.str()); |
| 912 | } |
| 913 | } |
| 914 | |
| 915 | TEST_F(GraphicsRobustAccessTest, ACStructNonConstantFail) { |
| 916 | for (auto* ac : AccessChains()) { |
| 917 | std::ostringstream shaders; |
| 918 | shaders << ShaderPreambleAC({"struct", "i"}) << |
| 919 | |
| 920 | TypesVoid() << TypesInt() << TypesFloat() << R"( |
| 921 | %float_2 = OpConstant %float 2 |
| 922 | %struct = OpTypeStruct %float %float %float |
| 923 | %var_ty = OpTypePointer Function %struct |
| 924 | %ptr_ty = OpTypePointer Function %float |
| 925 | %i = OpUndef %int |
| 926 | )" << MainPrefix() << R"( |
| 927 | %var = OpVariable %var_ty Function |
| 928 | ; CHECK: Member index into struct is not a constant integer |
| 929 | ; CHECK-SAME: %i = OpUndef %int |
| 930 | )" |
| 931 | << ACCheckFail(ac, "%i", "%i") << MainSuffix(); |
| 932 | SinglePassRunAndFail<GraphicsRobustAccessPass>(shaders.str()); |
| 933 | } |
| 934 | } |
| 935 | |
| 936 | TEST_F(GraphicsRobustAccessTest, ACStructExcessFail) { |
| 937 | for (auto* ac : AccessChains()) { |
| 938 | std::ostringstream shaders; |
| 939 | shaders << ShaderPreambleAC({"struct", "i"}) << TypesVoid() << TypesInt() |
| 940 | << TypesFloat() << R"( |
| 941 | %struct = OpTypeStruct %float %float %float |
| 942 | %var_ty = OpTypePointer Function %struct |
| 943 | %ptr_ty = OpTypePointer Function %float |
| 944 | %i = OpConstant %int 4 |
| 945 | )" << MainPrefix() << R"( |
| 946 | %var = OpVariable %var_ty Function |
| 947 | ; CHECK: Member index 4 is out of bounds for struct type: |
| 948 | ; CHECK-SAME: %struct = OpTypeStruct %float %float %float |
| 949 | )" |
| 950 | << ACCheckFail(ac, "%i", "%i") << MainSuffix(); |
| 951 | SinglePassRunAndFail<GraphicsRobustAccessPass>(shaders.str()); |
| 952 | } |
| 953 | } |
| 954 | |
| 955 | TEST_F(GraphicsRobustAccessTest, ACStructNegativeFail) { |
| 956 | for (auto* ac : AccessChains()) { |
| 957 | std::ostringstream shaders; |
| 958 | shaders << ShaderPreambleAC({"struct", "i"}) << TypesVoid() << TypesInt() |
| 959 | << TypesFloat() << R"( |
| 960 | %struct = OpTypeStruct %float %float %float |
| 961 | %var_ty = OpTypePointer Function %struct |
| 962 | %ptr_ty = OpTypePointer Function %float |
| 963 | %i = OpConstant %int -1 |
| 964 | )" << MainPrefix() << R"( |
| 965 | %var = OpVariable %var_ty Function |
| 966 | ; CHECK: Member index -1 is out of bounds for struct type: |
| 967 | ; CHECK-SAME: %struct = OpTypeStruct %float %float %float |
| 968 | )" |
| 969 | << ACCheckFail(ac, "%i", "%i") << MainSuffix(); |
| 970 | SinglePassRunAndFail<GraphicsRobustAccessPass>(shaders.str()); |
| 971 | } |
| 972 | } |
| 973 | |
| 974 | TEST_F(GraphicsRobustAccessTest, ACRTArrayLeastInboundClamped) { |
| 975 | for (auto* ac : AccessChains()) { |
| 976 | std::ostringstream shaders; |
Ben Clayton | d552f63 | 2019-11-18 11:18:41 +0000 | [diff] [blame] | 977 | shaders << ShaderPreambleAC() << "OpDecorate %rtarr ArrayStride 4 " |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 978 | << DecoSSBO() << TypesVoid() << TypesInt() << TypesFloat() << R"( |
| 979 | %rtarr = OpTypeRuntimeArray %float |
| 980 | %ssbo_s = OpTypeStruct %uint %uint %rtarr |
| 981 | %var_ty = OpTypePointer Uniform %ssbo_s |
| 982 | %ptr_ty = OpTypePointer Uniform %float |
| 983 | %var = OpVariable %var_ty Uniform |
| 984 | %int_0 = OpConstant %int 0 |
| 985 | %int_2 = OpConstant %int 2 |
| 986 | ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 987 | ; CHECK-DAG: %int_1 = OpConstant %int 1 |
| 988 | ; CHECK-DAG: %[[intmax:\w+]] = OpConstant %int 2147483647 |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 989 | ; CHECK: OpLabel |
| 990 | ; CHECK: %[[arrlen:\w+]] = OpArrayLength %uint %var 2 |
| 991 | ; CHECK: %[[max:\w+]] = OpISub %int %[[arrlen]] %int_1 |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 992 | ; CHECK: %[[smin:\w+]] = OpExtInst %int %[[GLSLSTD450]] UMin %[[max]] %[[intmax]] |
| 993 | ; CHECK: %[[clamp:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %int_0 %int_0 %[[smin]] |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 994 | )" |
| 995 | << MainPrefix() << ACCheck(ac, "%int_2 %int_0", "%int_2 %[[clamp]]") |
| 996 | << MainSuffix(); |
| 997 | SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true); |
| 998 | } |
| 999 | } |
| 1000 | |
| 1001 | TEST_F(GraphicsRobustAccessTest, ACRTArrayGeneralShortIndexClamped) { |
| 1002 | for (auto* ac : AccessChains()) { |
| 1003 | std::ostringstream shaders; |
| 1004 | shaders << "OpCapability Int16\n" |
Ben Clayton | d552f63 | 2019-11-18 11:18:41 +0000 | [diff] [blame] | 1005 | << ShaderPreambleAC({"i"}) << "OpDecorate %rtarr ArrayStride 4 " |
| 1006 | << DecoSSBO() << TypesVoid() << TypesShort() << TypesFloat() << R"( |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 1007 | %rtarr = OpTypeRuntimeArray %float |
| 1008 | %ssbo_s = OpTypeStruct %short %short %rtarr |
| 1009 | %var_ty = OpTypePointer Uniform %ssbo_s |
| 1010 | %ptr_ty = OpTypePointer Uniform %float |
| 1011 | %var = OpVariable %var_ty Uniform |
| 1012 | %short_2 = OpConstant %short 2 |
| 1013 | %i = OpUndef %short |
| 1014 | ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" |
| 1015 | ; CHECK: %uint = OpTypeInt 32 0 |
| 1016 | ; CHECK-DAG: %uint_1 = OpConstant %uint 1 |
| 1017 | ; CHECK-DAG: %uint_0 = OpConstant %uint 0 |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 1018 | ; CHECK-DAG: %[[intmax:\w+]] = OpConstant %uint 2147483647 |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 1019 | ; CHECK: OpLabel |
| 1020 | ; CHECK: %[[arrlen:\w+]] = OpArrayLength %uint %var 2 |
| 1021 | ; CHECK-DAG: %[[max:\w+]] = OpISub %uint %[[arrlen]] %uint_1 |
| 1022 | ; CHECK-DAG: %[[i_ext:\w+]] = OpSConvert %uint %i |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 1023 | ; CHECK: %[[smin:\w+]] = OpExtInst %uint %[[GLSLSTD450]] UMin %[[max]] %[[intmax]] |
| 1024 | ; CHECK: %[[clamp:\w+]] = OpExtInst %uint %[[GLSLSTD450]] SClamp %[[i_ext]] %uint_0 %[[smin]] |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 1025 | )" |
| 1026 | << MainPrefix() << ACCheck(ac, "%short_2 %i", "%short_2 %[[clamp]]") |
| 1027 | << MainSuffix(); |
| 1028 | SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true); |
| 1029 | } |
| 1030 | } |
| 1031 | |
| 1032 | TEST_F(GraphicsRobustAccessTest, ACRTArrayGeneralUShortIndexClamped) { |
| 1033 | for (auto* ac : AccessChains()) { |
| 1034 | std::ostringstream shaders; |
| 1035 | shaders << "OpCapability Int16\n" |
Ben Clayton | d552f63 | 2019-11-18 11:18:41 +0000 | [diff] [blame] | 1036 | << ShaderPreambleAC({"i"}) << "OpDecorate %rtarr ArrayStride 4 " |
| 1037 | << DecoSSBO() << TypesVoid() << TypesShort() << TypesFloat() << R"( |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 1038 | %rtarr = OpTypeRuntimeArray %float |
| 1039 | %ssbo_s = OpTypeStruct %short %short %rtarr |
| 1040 | %var_ty = OpTypePointer Uniform %ssbo_s |
| 1041 | %ptr_ty = OpTypePointer Uniform %float |
| 1042 | %var = OpVariable %var_ty Uniform |
| 1043 | %short_2 = OpConstant %short 2 |
| 1044 | %i = OpUndef %ushort |
| 1045 | ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" |
| 1046 | ; CHECK: %uint = OpTypeInt 32 0 |
| 1047 | ; CHECK-DAG: %uint_1 = OpConstant %uint 1 |
| 1048 | ; CHECK-DAG: %uint_0 = OpConstant %uint 0 |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 1049 | ; CHECK-DAG: %[[intmax:\w+]] = OpConstant %uint 2147483647 |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 1050 | ; CHECK: OpLabel |
| 1051 | ; CHECK: %[[arrlen:\w+]] = OpArrayLength %uint %var 2 |
| 1052 | ; CHECK-DAG: %[[max:\w+]] = OpISub %uint %[[arrlen]] %uint_1 |
| 1053 | ; CHECK-DAG: %[[i_ext:\w+]] = OpSConvert %uint %i |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 1054 | ; CHECK: %[[smin:\w+]] = OpExtInst %uint %[[GLSLSTD450]] UMin %[[max]] %[[intmax]] |
| 1055 | ; CHECK: %[[clamp:\w+]] = OpExtInst %uint %[[GLSLSTD450]] SClamp %[[i_ext]] %uint_0 %[[smin]] |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 1056 | )" |
| 1057 | << MainPrefix() << ACCheck(ac, "%short_2 %i", "%short_2 %[[clamp]]") |
| 1058 | << MainSuffix(); |
| 1059 | SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true); |
| 1060 | } |
| 1061 | } |
| 1062 | |
| 1063 | TEST_F(GraphicsRobustAccessTest, ACRTArrayGeneralIntIndexClamped) { |
| 1064 | for (auto* ac : AccessChains()) { |
| 1065 | std::ostringstream shaders; |
Ben Clayton | d552f63 | 2019-11-18 11:18:41 +0000 | [diff] [blame] | 1066 | shaders << ShaderPreambleAC({"i"}) << "OpDecorate %rtarr ArrayStride 4 " |
| 1067 | << DecoSSBO() << TypesVoid() << TypesInt() << TypesFloat() << R"( |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 1068 | %rtarr = OpTypeRuntimeArray %float |
| 1069 | %ssbo_s = OpTypeStruct %int %int %rtarr |
| 1070 | %var_ty = OpTypePointer Uniform %ssbo_s |
| 1071 | %ptr_ty = OpTypePointer Uniform %float |
| 1072 | %var = OpVariable %var_ty Uniform |
| 1073 | %int_2 = OpConstant %int 2 |
| 1074 | %i = OpUndef %int |
| 1075 | ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" |
| 1076 | ; CHECK-DAG: %int_1 = OpConstant %int 1 |
| 1077 | ; CHECK-DAG: %int_0 = OpConstant %int 0 |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 1078 | ; CHECK-DAG: %[[intmax:\w+]] = OpConstant %int 2147483647 |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 1079 | ; CHECK: OpLabel |
| 1080 | ; CHECK: %[[arrlen:\w+]] = OpArrayLength %uint %var 2 |
| 1081 | ; CHECK: %[[max:\w+]] = OpISub %int %[[arrlen]] %int_1 |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 1082 | ; CHECK: %[[smin:\w+]] = OpExtInst %int %[[GLSLSTD450]] UMin %[[max]] %[[intmax]] |
| 1083 | ; CHECK: %[[clamp:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %i %int_0 %[[smin]] |
Ben Clayton | d552f63 | 2019-11-18 11:18:41 +0000 | [diff] [blame] | 1084 | )" |
| 1085 | << MainPrefix() << ACCheck(ac, "%int_2 %i", "%int_2 %[[clamp]]") |
| 1086 | << MainSuffix(); |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 1087 | SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true); |
| 1088 | } |
| 1089 | } |
| 1090 | |
| 1091 | TEST_F(GraphicsRobustAccessTest, ACRTArrayGeneralUIntIndexClamped) { |
| 1092 | for (auto* ac : AccessChains()) { |
| 1093 | std::ostringstream shaders; |
Ben Clayton | d552f63 | 2019-11-18 11:18:41 +0000 | [diff] [blame] | 1094 | shaders << ShaderPreambleAC({"i"}) << "OpDecorate %rtarr ArrayStride 4 " |
| 1095 | << DecoSSBO() << TypesVoid() << TypesInt() << TypesFloat() << R"( |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 1096 | %rtarr = OpTypeRuntimeArray %float |
| 1097 | %ssbo_s = OpTypeStruct %int %int %rtarr |
| 1098 | %var_ty = OpTypePointer Uniform %ssbo_s |
| 1099 | %ptr_ty = OpTypePointer Uniform %float |
| 1100 | %var = OpVariable %var_ty Uniform |
| 1101 | %int_2 = OpConstant %int 2 |
| 1102 | %i = OpUndef %uint |
| 1103 | ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" |
| 1104 | ; CHECK-DAG: %uint_1 = OpConstant %uint 1 |
| 1105 | ; CHECK-DAG: %uint_0 = OpConstant %uint 0 |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 1106 | ; CHECK-DAG: %[[intmax:\w+]] = OpConstant %uint 2147483647 |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 1107 | ; CHECK: OpLabel |
| 1108 | ; CHECK: %[[arrlen:\w+]] = OpArrayLength %uint %var 2 |
| 1109 | ; CHECK: %[[max:\w+]] = OpISub %uint %[[arrlen]] %uint_1 |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 1110 | ; CHECK: %[[smin:\w+]] = OpExtInst %uint %[[GLSLSTD450]] UMin %[[max]] %[[intmax]] |
| 1111 | ; CHECK: %[[clamp:\w+]] = OpExtInst %uint %[[GLSLSTD450]] SClamp %i %uint_0 %[[smin]] |
Ben Clayton | d552f63 | 2019-11-18 11:18:41 +0000 | [diff] [blame] | 1112 | )" |
| 1113 | << MainPrefix() << ACCheck(ac, "%int_2 %i", "%int_2 %[[clamp]]") |
| 1114 | << MainSuffix(); |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 1115 | SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true); |
| 1116 | } |
| 1117 | } |
| 1118 | |
| 1119 | TEST_F(GraphicsRobustAccessTest, ACRTArrayGeneralLongIndexClamped) { |
| 1120 | for (auto* ac : AccessChains()) { |
| 1121 | std::ostringstream shaders; |
| 1122 | shaders << "OpCapability Int64" << ShaderPreambleAC({"i"}) |
Ben Clayton | d552f63 | 2019-11-18 11:18:41 +0000 | [diff] [blame] | 1123 | << "OpDecorate %rtarr ArrayStride 4 " << DecoSSBO() << TypesVoid() |
| 1124 | << TypesInt() << TypesLong() << TypesFloat() << R"( |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 1125 | %rtarr = OpTypeRuntimeArray %float |
| 1126 | %ssbo_s = OpTypeStruct %int %int %rtarr |
| 1127 | %var_ty = OpTypePointer Uniform %ssbo_s |
| 1128 | %ptr_ty = OpTypePointer Uniform %float |
| 1129 | %var = OpVariable %var_ty Uniform |
| 1130 | %int_2 = OpConstant %int 2 |
| 1131 | %i = OpUndef %long |
| 1132 | ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" |
| 1133 | ; CHECK-DAG: %long_0 = OpConstant %long 0 |
| 1134 | ; CHECK-DAG: %long_1 = OpConstant %long 1 |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 1135 | ; CHECK-DAG: %[[longmax:\w+]] = OpConstant %long 9223372036854775807 |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 1136 | ; CHECK: OpLabel |
| 1137 | ; CHECK: %[[arrlen:\w+]] = OpArrayLength %uint %var 2 |
| 1138 | ; CHECK: %[[arrlen_ext:\w+]] = OpUConvert %ulong %[[arrlen]] |
| 1139 | ; CHECK: %[[max:\w+]] = OpISub %long %[[arrlen_ext]] %long_1 |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 1140 | ; CHECK: %[[smin:\w+]] = OpExtInst %long %[[GLSLSTD450]] UMin %[[max]] %[[longmax]] |
| 1141 | ; CHECK: %[[clamp:\w+]] = OpExtInst %long %[[GLSLSTD450]] SClamp %i %long_0 %[[smin]] |
Ben Clayton | d552f63 | 2019-11-18 11:18:41 +0000 | [diff] [blame] | 1142 | )" << MainPrefix() |
| 1143 | << ACCheck(ac, "%int_2 %i", "%int_2 %[[clamp]]") << MainSuffix(); |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 1144 | SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true); |
| 1145 | } |
| 1146 | } |
| 1147 | |
| 1148 | TEST_F(GraphicsRobustAccessTest, ACRTArrayGeneralULongIndexClamped) { |
| 1149 | for (auto* ac : AccessChains()) { |
| 1150 | std::ostringstream shaders; |
| 1151 | shaders << "OpCapability Int64" << ShaderPreambleAC({"i"}) |
Ben Clayton | d552f63 | 2019-11-18 11:18:41 +0000 | [diff] [blame] | 1152 | << "OpDecorate %rtarr ArrayStride 4 " << DecoSSBO() << TypesVoid() |
| 1153 | << TypesInt() << TypesLong() << TypesFloat() << R"( |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 1154 | %rtarr = OpTypeRuntimeArray %float |
| 1155 | %ssbo_s = OpTypeStruct %int %int %rtarr |
| 1156 | %var_ty = OpTypePointer Uniform %ssbo_s |
| 1157 | %ptr_ty = OpTypePointer Uniform %float |
| 1158 | %var = OpVariable %var_ty Uniform |
| 1159 | %int_2 = OpConstant %int 2 |
| 1160 | %i = OpUndef %ulong |
| 1161 | ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" |
| 1162 | ; CHECK-DAG: %ulong_0 = OpConstant %ulong 0 |
| 1163 | ; CHECK-DAG: %ulong_1 = OpConstant %ulong 1 |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 1164 | ; CHECK-DAG: %[[longmax:\w+]] = OpConstant %ulong 9223372036854775807 |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 1165 | ; CHECK: OpLabel |
| 1166 | ; CHECK: %[[arrlen:\w+]] = OpArrayLength %uint %var 2 |
| 1167 | ; CHECK: %[[arrlen_ext:\w+]] = OpUConvert %ulong %[[arrlen]] |
| 1168 | ; CHECK: %[[max:\w+]] = OpISub %ulong %[[arrlen_ext]] %ulong_1 |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 1169 | ; CHECK: %[[smin:\w+]] = OpExtInst %ulong %[[GLSLSTD450]] UMin %[[max]] %[[longmax]] |
| 1170 | ; CHECK: %[[clamp:\w+]] = OpExtInst %ulong %[[GLSLSTD450]] SClamp %i %ulong_0 %[[smin]] |
Ben Clayton | d552f63 | 2019-11-18 11:18:41 +0000 | [diff] [blame] | 1171 | )" << MainPrefix() |
| 1172 | << ACCheck(ac, "%int_2 %i", "%int_2 %[[clamp]]") << MainSuffix(); |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 1173 | SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true); |
| 1174 | } |
| 1175 | } |
| 1176 | |
| 1177 | TEST_F(GraphicsRobustAccessTest, ACRTArrayStructVectorElem) { |
| 1178 | // The point of this test is that the access chain can have indices past the |
| 1179 | // index into the runtime array. For good measure, the index into the final |
| 1180 | // struct is out of bounds. We have to clamp that index too. |
| 1181 | for (auto* ac : AccessChains()) { |
| 1182 | std::ostringstream shaders; |
| 1183 | shaders << ShaderPreambleAC({"i", "j"}) |
Ben Clayton | d552f63 | 2019-11-18 11:18:41 +0000 | [diff] [blame] | 1184 | << "OpDecorate %rtarr ArrayStride 32\n" |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 1185 | << DecoSSBO() << "OpMemberDecorate %rtelem 0 Offset 0\n" |
| 1186 | << "OpMemberDecorate %rtelem 1 Offset 16\n" |
| 1187 | << TypesVoid() << TypesInt() << TypesFloat() << R"( |
| 1188 | %v4float = OpTypeVector %float 4 |
| 1189 | %rtelem = OpTypeStruct %v4float %v4float |
| 1190 | %rtarr = OpTypeRuntimeArray %rtelem |
| 1191 | %ssbo_s = OpTypeStruct %int %int %rtarr |
| 1192 | %var_ty = OpTypePointer Uniform %ssbo_s |
| 1193 | %ptr_ty = OpTypePointer Uniform %float |
| 1194 | %var = OpVariable %var_ty Uniform |
| 1195 | %int_1 = OpConstant %int 1 |
| 1196 | %int_2 = OpConstant %int 2 |
| 1197 | %i = OpUndef %int |
| 1198 | %j = OpUndef %int |
| 1199 | ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" |
| 1200 | ; CHECK-DAG: %int_0 = OpConstant %int 0 |
| 1201 | ; CHECK-DAG: %int_3 = OpConstant %int 3 |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 1202 | ; CHECK-DAG: %[[intmax:\w+]] = OpConstant %int 2147483647 |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 1203 | ; CHECK: OpLabel |
| 1204 | ; CHECK: %[[arrlen:\w+]] = OpArrayLength %uint %var 2 |
| 1205 | ; CHECK: %[[max:\w+]] = OpISub %int %[[arrlen]] %int_1 |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 1206 | ; CHECK: %[[smin:\w+]] = OpExtInst %int %[[GLSLSTD450]] UMin %[[max]] %[[intmax]] |
| 1207 | ; CHECK: %[[clamp_i:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %i %int_0 %[[smin]] |
| 1208 | ; CHECK: %[[clamp_j:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %j %int_0 %int_3 |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 1209 | )" << MainPrefix() |
| 1210 | << ACCheck(ac, "%int_2 %i %int_1 %j", |
| 1211 | "%int_2 %[[clamp_i]] %int_1 %[[clamp_j]]") |
| 1212 | << MainSuffix(); |
| 1213 | SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true); |
| 1214 | } |
| 1215 | } |
| 1216 | |
| 1217 | TEST_F(GraphicsRobustAccessTest, ACArrayRTArrayStructVectorElem) { |
| 1218 | // Now add an additional level of arrays around the Block-decorated struct. |
| 1219 | for (auto* ac : AccessChains()) { |
| 1220 | std::ostringstream shaders; |
| 1221 | shaders << ShaderPreambleAC({"i", "ssbo_s"}) |
Ben Clayton | d552f63 | 2019-11-18 11:18:41 +0000 | [diff] [blame] | 1222 | << "OpDecorate %rtarr ArrayStride 32\n" |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 1223 | << DecoSSBO() << "OpMemberDecorate %rtelem 0 Offset 0\n" |
| 1224 | << "OpMemberDecorate %rtelem 1 Offset 16\n" |
| 1225 | << TypesVoid() << TypesInt() << TypesFloat() << R"( |
| 1226 | %v4float = OpTypeVector %float 4 |
| 1227 | %rtelem = OpTypeStruct %v4float %v4float |
| 1228 | %rtarr = OpTypeRuntimeArray %rtelem |
| 1229 | %ssbo_s = OpTypeStruct %int %int %rtarr |
| 1230 | %arr_size = OpConstant %int 10 |
| 1231 | %arr_ssbo = OpTypeArray %ssbo_s %arr_size |
| 1232 | %var_ty = OpTypePointer Uniform %arr_ssbo |
| 1233 | %ptr_ty = OpTypePointer Uniform %float |
| 1234 | %var = OpVariable %var_ty Uniform |
| 1235 | %int_1 = OpConstant %int 1 |
| 1236 | %int_2 = OpConstant %int 2 |
| 1237 | %int_17 = OpConstant %int 17 |
| 1238 | %i = OpUndef %int |
| 1239 | ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" |
| 1240 | ; CHECK-DAG: %[[ssbo_p:\w+]] = OpTypePointer Uniform %ssbo_s |
| 1241 | ; CHECK-DAG: %int_0 = OpConstant %int 0 |
| 1242 | ; CHECK-DAG: %int_9 = OpConstant %int 9 |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 1243 | ; CHECK-DAG: %[[intmax:\w+]] = OpConstant %int 2147483647 |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 1244 | ; CHECK: OpLabel |
sugoi1 | b398bf3 | 2022-02-18 10:27:28 -0500 | [diff] [blame^] | 1245 | ; This access chain is manufactured only so we can compute the array length. |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 1246 | ; Note that the %int_9 is already clamped |
| 1247 | ; CHECK: %[[ssbo_base:\w+]] = )" << ac |
| 1248 | << R"( %[[ssbo_p]] %var %int_9 |
| 1249 | ; CHECK: %[[arrlen:\w+]] = OpArrayLength %uint %[[ssbo_base]] 2 |
| 1250 | ; CHECK: %[[max:\w+]] = OpISub %int %[[arrlen]] %int_1 |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 1251 | ; CHECK: %[[smin:\w+]] = OpExtInst %int %[[GLSLSTD450]] UMin %[[max]] %[[intmax]] |
| 1252 | ; CHECK: %[[clamp_i:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %i %int_0 %[[smin]] |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 1253 | )" << MainPrefix() |
| 1254 | << ACCheck(ac, "%int_17 %int_2 %i %int_1 %int_2", |
| 1255 | "%int_9 %int_2 %[[clamp_i]] %int_1 %int_2") |
| 1256 | << MainSuffix(); |
| 1257 | SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true); |
| 1258 | } |
| 1259 | } |
| 1260 | |
| 1261 | TEST_F(GraphicsRobustAccessTest, ACSplitACArrayRTArrayStructVectorElem) { |
| 1262 | // Split the address calculation across two access chains. Force |
| 1263 | // the transform to walk up the access chains to find the base variable. |
| 1264 | for (auto* ac : AccessChains()) { |
| 1265 | std::ostringstream shaders; |
| 1266 | shaders << ShaderPreambleAC({"i", "j", "k", "ssbo_s", "ssbo_pty", |
| 1267 | "rtarr_pty", "ac_ssbo", "ac_rtarr"}) |
Ben Clayton | d552f63 | 2019-11-18 11:18:41 +0000 | [diff] [blame] | 1268 | << "OpDecorate %rtarr ArrayStride 32\n" |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 1269 | << DecoSSBO() << "OpMemberDecorate %rtelem 0 Offset 0\n" |
| 1270 | << "OpMemberDecorate %rtelem 1 Offset 16\n" |
| 1271 | << TypesVoid() << TypesInt() << TypesFloat() << R"( |
| 1272 | %v4float = OpTypeVector %float 4 |
| 1273 | %rtelem = OpTypeStruct %v4float %v4float |
| 1274 | %rtarr = OpTypeRuntimeArray %rtelem |
| 1275 | %ssbo_s = OpTypeStruct %int %int %rtarr |
| 1276 | %arr_size = OpConstant %int 10 |
| 1277 | %arr_ssbo = OpTypeArray %ssbo_s %arr_size |
| 1278 | %var_ty = OpTypePointer Uniform %arr_ssbo |
| 1279 | %ssbo_pty = OpTypePointer Uniform %ssbo_s |
| 1280 | %rtarr_pty = OpTypePointer Uniform %rtarr |
| 1281 | %ptr_ty = OpTypePointer Uniform %float |
| 1282 | %var = OpVariable %var_ty Uniform |
| 1283 | %int_1 = OpConstant %int 1 |
| 1284 | %int_2 = OpConstant %int 2 |
| 1285 | %i = OpUndef %int |
| 1286 | %j = OpUndef %int |
| 1287 | %k = OpUndef %int |
| 1288 | ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" |
| 1289 | ; CHECK-DAG: %int_0 = OpConstant %int 0 |
| 1290 | ; CHECK-DAG: %int_9 = OpConstant %int 9 |
| 1291 | ; CHECK-DAG: %int_3 = OpConstant %int 3 |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 1292 | ; CHECK-DAG: %[[intmax:\w+]] = OpConstant %int 2147483647 |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 1293 | ; CHECK: OpLabel |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 1294 | ; CHECK: %[[clamp_i:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %i %int_0 %int_9 |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 1295 | ; CHECK: %ac_ssbo = )" << ac |
| 1296 | << R"( %ssbo_pty %var %[[clamp_i]] |
| 1297 | ; CHECK: %ac_rtarr = )" |
| 1298 | << ac << R"( %rtarr_pty %ac_ssbo %int_2 |
| 1299 | |
| 1300 | ; This is the interesting bit. This array length is needed for an OpAccessChain |
| 1301 | ; computing %ac, but the algorithm had to track back through %ac_rtarr's |
| 1302 | ; definition to find the base pointer %ac_ssbo. |
| 1303 | ; CHECK: %[[arrlen:\w+]] = OpArrayLength %uint %ac_ssbo 2 |
| 1304 | ; CHECK: %[[max:\w+]] = OpISub %int %[[arrlen]] %int_1 |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 1305 | ; CHECK: %[[smin:\w+]] = OpExtInst %int %[[GLSLSTD450]] UMin %[[max]] %[[intmax]] |
| 1306 | ; CHECK: %[[clamp_j:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %j %int_0 %[[smin]] |
| 1307 | ; CHECK: %[[clamp_k:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %k %int_0 %int_3 |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 1308 | ; CHECK: %ac = )" << ac |
| 1309 | << R"( %ptr_ty %ac_rtarr %[[clamp_j]] %int_1 %[[clamp_k]] |
| 1310 | ; CHECK-NOT: AccessChain |
| 1311 | )" << MainPrefix() |
| 1312 | << "%ac_ssbo = " << ac << " %ssbo_pty %var %i\n" |
| 1313 | << "%ac_rtarr = " << ac << " %rtarr_pty %ac_ssbo %int_2\n" |
| 1314 | << "%ac = " << ac << " %ptr_ty %ac_rtarr %j %int_1 %k\n" |
| 1315 | |
| 1316 | << MainSuffix(); |
| 1317 | SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true); |
| 1318 | } |
| 1319 | } |
| 1320 | |
| 1321 | TEST_F(GraphicsRobustAccessTest, |
| 1322 | ACSplitACArrayRTArrayStructVectorElemAcrossBasicBlocks) { |
| 1323 | // Split the address calculation across two access chains. Force |
| 1324 | // the transform to walk up the access chains to find the base variable. |
| 1325 | // This time, put the different access chains in different basic blocks. |
Alexis Hetu | 3eb4dd8 | 2020-10-29 21:37:20 -0400 | [diff] [blame] | 1326 | // This is an integrity check to ensure that we keep the instruction-to-block |
| 1327 | // mapping consistent. |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 1328 | for (auto* ac : AccessChains()) { |
| 1329 | std::ostringstream shaders; |
| 1330 | shaders << ShaderPreambleAC({"i", "j", "k", "bb1", "bb2", "ssbo_s", |
| 1331 | "ssbo_pty", "rtarr_pty", "ac_ssbo", |
| 1332 | "ac_rtarr"}) |
Ben Clayton | d552f63 | 2019-11-18 11:18:41 +0000 | [diff] [blame] | 1333 | << "OpDecorate %rtarr ArrayStride 32\n" |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 1334 | << DecoSSBO() << "OpMemberDecorate %rtelem 0 Offset 0\n" |
| 1335 | << "OpMemberDecorate %rtelem 1 Offset 16\n" |
| 1336 | << TypesVoid() << TypesInt() << TypesFloat() << R"( |
| 1337 | %v4float = OpTypeVector %float 4 |
| 1338 | %rtelem = OpTypeStruct %v4float %v4float |
| 1339 | %rtarr = OpTypeRuntimeArray %rtelem |
| 1340 | %ssbo_s = OpTypeStruct %int %int %rtarr |
| 1341 | %arr_size = OpConstant %int 10 |
| 1342 | %arr_ssbo = OpTypeArray %ssbo_s %arr_size |
| 1343 | %var_ty = OpTypePointer Uniform %arr_ssbo |
| 1344 | %ssbo_pty = OpTypePointer Uniform %ssbo_s |
| 1345 | %rtarr_pty = OpTypePointer Uniform %rtarr |
| 1346 | %ptr_ty = OpTypePointer Uniform %float |
| 1347 | %var = OpVariable %var_ty Uniform |
| 1348 | %int_1 = OpConstant %int 1 |
| 1349 | %int_2 = OpConstant %int 2 |
| 1350 | %i = OpUndef %int |
| 1351 | %j = OpUndef %int |
| 1352 | %k = OpUndef %int |
| 1353 | ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" |
| 1354 | ; CHECK-DAG: %int_0 = OpConstant %int 0 |
| 1355 | ; CHECK-DAG: %int_9 = OpConstant %int 9 |
| 1356 | ; CHECK-DAG: %int_3 = OpConstant %int 3 |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 1357 | ; CHECK-DAG: %[[intmax:\w+]] = OpConstant %int 2147483647 |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 1358 | ; CHECK: OpLabel |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 1359 | ; CHECK: %[[clamp_i:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %i %int_0 %int_9 |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 1360 | ; CHECK: %ac_ssbo = )" << ac |
| 1361 | << R"( %ssbo_pty %var %[[clamp_i]] |
| 1362 | ; CHECK: %bb1 = OpLabel |
| 1363 | ; CHECK: %ac_rtarr = )" |
| 1364 | << ac << R"( %rtarr_pty %ac_ssbo %int_2 |
| 1365 | ; CHECK: %bb2 = OpLabel |
| 1366 | |
| 1367 | ; This is the interesting bit. This array length is needed for an OpAccessChain |
| 1368 | ; computing %ac, but the algorithm had to track back through %ac_rtarr's |
| 1369 | ; definition to find the base pointer %ac_ssbo. |
| 1370 | ; CHECK: %[[arrlen:\w+]] = OpArrayLength %uint %ac_ssbo 2 |
| 1371 | ; CHECK: %[[max:\w+]] = OpISub %int %[[arrlen]] %int_1 |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 1372 | ; CHECK: %[[smin:\w+]] = OpExtInst %int %[[GLSLSTD450]] UMin %[[max]] %[[intmax]] |
| 1373 | ; CHECK: %[[clamp_j:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %j %int_0 %[[smin]] |
| 1374 | ; CHECK: %[[clamp_k:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %k %int_0 %int_3 |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 1375 | ; CHECK: %ac = )" << ac |
| 1376 | << R"( %ptr_ty %ac_rtarr %[[clamp_j]] %int_1 %[[clamp_k]] |
| 1377 | ; CHECK-NOT: AccessChain |
| 1378 | )" << MainPrefix() |
| 1379 | << "%ac_ssbo = " << ac << " %ssbo_pty %var %i\n" |
| 1380 | << "OpBranch %bb1\n%bb1 = OpLabel\n" |
| 1381 | << "%ac_rtarr = " << ac << " %rtarr_pty %ac_ssbo %int_2\n" |
| 1382 | << "OpBranch %bb2\n%bb2 = OpLabel\n" |
| 1383 | << "%ac = " << ac << " %ptr_ty %ac_rtarr %j %int_1 %k\n" |
| 1384 | |
| 1385 | << MainSuffix(); |
| 1386 | SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true); |
| 1387 | } |
| 1388 | } |
| 1389 | |
Alexis Hetu | 3eb4dd8 | 2020-10-29 21:37:20 -0400 | [diff] [blame] | 1390 | TEST_F(GraphicsRobustAccessTest, bug3813) { |
| 1391 | // This shader comes from Dawn's |
| 1392 | // TextureViewSamplingTest.TextureCubeMapOnWholeTexture, converted from GLSL |
| 1393 | // by glslang. |
| 1394 | // The pass was inserting a signed 32-bit int type, but not correctly marking |
| 1395 | // the shader as changed. |
| 1396 | std::string shader = R"( |
| 1397 | ; SPIR-V |
| 1398 | ; Version: 1.0 |
| 1399 | ; Generator: Google Shaderc over Glslang; 10 |
| 1400 | ; Bound: 46 |
| 1401 | ; Schema: 0 |
| 1402 | OpCapability Shader |
| 1403 | %1 = OpExtInstImport "GLSL.std.450" |
| 1404 | OpMemoryModel Logical GLSL450 |
| 1405 | OpEntryPoint Fragment %4 "main" %12 %29 |
| 1406 | OpExecutionMode %4 OriginUpperLeft |
| 1407 | OpSource GLSL 450 |
| 1408 | OpSourceExtension "GL_GOOGLE_cpp_style_line_directive" |
| 1409 | OpSourceExtension "GL_GOOGLE_include_directive" |
| 1410 | OpName %4 "main" |
| 1411 | OpName %8 "sc" |
| 1412 | OpName %12 "texCoord" |
| 1413 | OpName %21 "tc" |
| 1414 | OpName %29 "fragColor" |
| 1415 | OpName %32 "texture0" |
| 1416 | OpName %36 "sampler0" |
| 1417 | OpDecorate %12 Location 0 |
| 1418 | OpDecorate %29 Location 0 |
| 1419 | OpDecorate %32 DescriptorSet 0 |
| 1420 | OpDecorate %32 Binding 1 |
| 1421 | OpDecorate %36 DescriptorSet 0 |
| 1422 | OpDecorate %36 Binding 0 |
| 1423 | %2 = OpTypeVoid |
| 1424 | %3 = OpTypeFunction %2 |
| 1425 | %6 = OpTypeFloat 32 |
| 1426 | %7 = OpTypePointer Function %6 |
| 1427 | %9 = OpConstant %6 2 |
| 1428 | %10 = OpTypeVector %6 2 |
| 1429 | %11 = OpTypePointer Input %10 |
| 1430 | %12 = OpVariable %11 Input |
| 1431 | %13 = OpTypeInt 32 0 |
| 1432 | %14 = OpConstant %13 0 |
| 1433 | %15 = OpTypePointer Input %6 |
| 1434 | %19 = OpConstant %6 1 |
| 1435 | %22 = OpConstant %13 1 |
| 1436 | %27 = OpTypeVector %6 4 |
| 1437 | %28 = OpTypePointer Output %27 |
| 1438 | %29 = OpVariable %28 Output |
| 1439 | %30 = OpTypeImage %6 Cube 0 0 0 1 Unknown |
| 1440 | %31 = OpTypePointer UniformConstant %30 |
| 1441 | %32 = OpVariable %31 UniformConstant |
| 1442 | %34 = OpTypeSampler |
| 1443 | %35 = OpTypePointer UniformConstant %34 |
| 1444 | %36 = OpVariable %35 UniformConstant |
| 1445 | %38 = OpTypeSampledImage %30 |
| 1446 | %43 = OpTypeVector %6 3 |
| 1447 | %4 = OpFunction %2 None %3 |
| 1448 | %5 = OpLabel |
| 1449 | %8 = OpVariable %7 Function |
| 1450 | %21 = OpVariable %7 Function |
| 1451 | %16 = OpAccessChain %15 %12 %14 |
| 1452 | %17 = OpLoad %6 %16 |
| 1453 | %18 = OpFMul %6 %9 %17 |
| 1454 | %20 = OpFSub %6 %18 %19 |
| 1455 | OpStore %8 %20 |
| 1456 | %23 = OpAccessChain %15 %12 %22 |
| 1457 | %24 = OpLoad %6 %23 |
| 1458 | %25 = OpFMul %6 %9 %24 |
| 1459 | %26 = OpFSub %6 %25 %19 |
| 1460 | OpStore %21 %26 |
| 1461 | %33 = OpLoad %30 %32 |
| 1462 | %37 = OpLoad %34 %36 |
| 1463 | %39 = OpSampledImage %38 %33 %37 |
| 1464 | %40 = OpLoad %6 %21 |
| 1465 | %41 = OpLoad %6 %8 |
| 1466 | %42 = OpFNegate %6 %41 |
| 1467 | %44 = OpCompositeConstruct %43 %19 %40 %42 |
| 1468 | %45 = OpImageSampleImplicitLod %27 %39 %44 |
| 1469 | OpStore %29 %45 |
| 1470 | OpReturn |
| 1471 | OpFunctionEnd |
| 1472 | )"; |
| 1473 | |
| 1474 | std::string expected = R"(OpCapability Shader |
| 1475 | %1 = OpExtInstImport "GLSL.std.450" |
| 1476 | OpMemoryModel Logical GLSL450 |
| 1477 | OpEntryPoint Fragment %main "main" %texCoord %fragColor |
| 1478 | OpExecutionMode %main OriginUpperLeft |
| 1479 | OpSource GLSL 450 |
| 1480 | OpSourceExtension "GL_GOOGLE_cpp_style_line_directive" |
| 1481 | OpSourceExtension "GL_GOOGLE_include_directive" |
| 1482 | OpName %main "main" |
| 1483 | OpName %sc "sc" |
| 1484 | OpName %texCoord "texCoord" |
| 1485 | OpName %tc "tc" |
| 1486 | OpName %fragColor "fragColor" |
| 1487 | OpName %texture0 "texture0" |
| 1488 | OpName %sampler0 "sampler0" |
| 1489 | OpDecorate %texCoord Location 0 |
| 1490 | OpDecorate %fragColor Location 0 |
| 1491 | OpDecorate %texture0 DescriptorSet 0 |
| 1492 | OpDecorate %texture0 Binding 1 |
| 1493 | OpDecorate %sampler0 DescriptorSet 0 |
| 1494 | OpDecorate %sampler0 Binding 0 |
| 1495 | %void = OpTypeVoid |
| 1496 | %10 = OpTypeFunction %void |
| 1497 | %float = OpTypeFloat 32 |
| 1498 | %_ptr_Function_float = OpTypePointer Function %float |
| 1499 | %float_2 = OpConstant %float 2 |
| 1500 | %v2float = OpTypeVector %float 2 |
| 1501 | %_ptr_Input_v2float = OpTypePointer Input %v2float |
| 1502 | %texCoord = OpVariable %_ptr_Input_v2float Input |
| 1503 | %uint = OpTypeInt 32 0 |
| 1504 | %uint_0 = OpConstant %uint 0 |
| 1505 | %_ptr_Input_float = OpTypePointer Input %float |
| 1506 | %float_1 = OpConstant %float 1 |
| 1507 | %uint_1 = OpConstant %uint 1 |
| 1508 | %v4float = OpTypeVector %float 4 |
| 1509 | %_ptr_Output_v4float = OpTypePointer Output %v4float |
| 1510 | %fragColor = OpVariable %_ptr_Output_v4float Output |
| 1511 | %23 = OpTypeImage %float Cube 0 0 0 1 Unknown |
| 1512 | %_ptr_UniformConstant_23 = OpTypePointer UniformConstant %23 |
| 1513 | %texture0 = OpVariable %_ptr_UniformConstant_23 UniformConstant |
| 1514 | %25 = OpTypeSampler |
| 1515 | %_ptr_UniformConstant_25 = OpTypePointer UniformConstant %25 |
| 1516 | %sampler0 = OpVariable %_ptr_UniformConstant_25 UniformConstant |
| 1517 | %27 = OpTypeSampledImage %23 |
| 1518 | %v3float = OpTypeVector %float 3 |
| 1519 | %int = OpTypeInt 32 1 |
| 1520 | %main = OpFunction %void None %10 |
| 1521 | %29 = OpLabel |
| 1522 | %sc = OpVariable %_ptr_Function_float Function |
| 1523 | %tc = OpVariable %_ptr_Function_float Function |
| 1524 | %30 = OpAccessChain %_ptr_Input_float %texCoord %uint_0 |
| 1525 | %31 = OpLoad %float %30 |
| 1526 | %32 = OpFMul %float %float_2 %31 |
| 1527 | %33 = OpFSub %float %32 %float_1 |
| 1528 | OpStore %sc %33 |
| 1529 | %34 = OpAccessChain %_ptr_Input_float %texCoord %uint_1 |
| 1530 | %35 = OpLoad %float %34 |
| 1531 | %36 = OpFMul %float %float_2 %35 |
| 1532 | %37 = OpFSub %float %36 %float_1 |
| 1533 | OpStore %tc %37 |
| 1534 | %38 = OpLoad %23 %texture0 |
| 1535 | %39 = OpLoad %25 %sampler0 |
| 1536 | %40 = OpSampledImage %27 %38 %39 |
| 1537 | %41 = OpLoad %float %tc |
| 1538 | %42 = OpLoad %float %sc |
| 1539 | %43 = OpFNegate %float %42 |
| 1540 | %44 = OpCompositeConstruct %v3float %float_1 %41 %43 |
| 1541 | %45 = OpImageSampleImplicitLod %v4float %40 %44 |
| 1542 | OpStore %fragColor %45 |
| 1543 | OpReturn |
| 1544 | OpFunctionEnd |
| 1545 | )"; |
| 1546 | |
| 1547 | SinglePassRunAndCheck<GraphicsRobustAccessPass>(shader, expected, false, |
| 1548 | true); |
| 1549 | } |
| 1550 | |
Alexis Hetu | 00e0af1 | 2021-11-08 08:57:46 -0500 | [diff] [blame] | 1551 | TEST_F(GraphicsRobustAccessTest, ReplaceIndexReportsChanged) { |
| 1552 | // A ClusterFuzz generated shader that triggered a |
| 1553 | // "Binary size unexpectedly changed despite the optimizer saying there was no |
| 1554 | // change" assertion. |
| 1555 | // See https://github.com/KhronosGroup/SPIRV-Tools/issues/4166. |
| 1556 | std::string shader = R"( |
| 1557 | ; SPIR-V |
| 1558 | ; Version: 1.0 |
| 1559 | ; Generator: Google Shaderc over Glslang; 245 |
| 1560 | ; Bound: 41 |
| 1561 | ; Schema: 0 |
| 1562 | OpCapability Shader |
| 1563 | %1 = OpExtInstImport "GLSL.std.450" |
| 1564 | OpMemoryModel Logical GLSL450 |
| 1565 | OpEntryPoint GLCompute %main "else" %gl_GlobalInvocationID |
| 1566 | OpExecutionMode %main LocalSize 1 1 3338665985 |
| 1567 | OpSource GLSL 450 |
| 1568 | OpSourceExtension "GL_GOOGLE_cpp_style_line_directive" |
| 1569 | OpSourceExtension "GL_GOOGLE_include_directive" |
| 1570 | OpName %main "main" |
| 1571 | OpName %index "index" |
| 1572 | OpName %gl_GlobalInvocationID "gl_GlobalInvocationID" |
| 1573 | OpName %S "S" |
| 1574 | OpMemberName %_struct_24 0 "" |
| 1575 | OpMemberName %_struct_24 1 "" |
| 1576 | OpName %Dst "Dst" |
| 1577 | OpMemberName %Dst 0 "s" |
| 1578 | OpName %dst "dst" |
| 1579 | OpName %Src "Src" |
| 1580 | OpMemberName %Src 0 "s" |
| 1581 | OpName %src "src" |
| 1582 | OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId |
| 1583 | OpMemberDecorate %_struct_24 0 Offset 64 |
| 1584 | OpMemberDecorate %_struct_24 1 Offset 8 |
| 1585 | OpDecorate %_arr__struct_24_uint_1 ArrayStride 16 |
| 1586 | OpMemberDecorate %Dst 0 Offset 0 |
| 1587 | OpDecorate %Dst BufferBlock |
| 1588 | OpDecorate %dst DescriptorSet 0 |
| 1589 | OpDecorate %dst Binding 1 |
| 1590 | OpDecorate %_arr__struct_24_uint_1_0 ArrayStride 16 |
| 1591 | OpMemberDecorate %Src 0 Offset 0 |
| 1592 | OpDecorate %Src Block |
| 1593 | OpDecorate %src DescriptorSet 0 |
| 1594 | OpDecorate %src Binding 0 |
| 1595 | %void = OpTypeVoid |
| 1596 | %3 = OpTypeFunction %void |
| 1597 | %uint = OpTypeInt 32 0 |
| 1598 | %_ptr_Function_uint = OpTypePointer Function %uint |
| 1599 | %v3uint = OpTypeVector %uint 3 |
| 1600 | %_ptr_Input_v3uint = OpTypePointer Input %v3uint |
| 1601 | %gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input |
| 1602 | %uint_4864 = OpConstant %uint 4864 |
| 1603 | %_ptr_Input_uint = OpTypePointer Input %uint |
| 1604 | %uint_1 = OpConstant %uint 1 |
| 1605 | %bool = OpTypeBool |
| 1606 | %v2uint = OpTypeVector %uint 2 |
| 1607 | %_struct_24 = OpTypeStruct %_ptr_Input_uint %v2uint |
| 1608 | %_arr__struct_24_uint_1 = OpTypeArray %_struct_24 %uint_1 |
| 1609 | %Dst = OpTypeStruct %_arr__struct_24_uint_1 |
| 1610 | %_ptr_Uniform_Dst = OpTypePointer Uniform %Dst |
| 1611 | %dst = OpVariable %_ptr_Uniform_Dst Uniform |
| 1612 | %int = OpTypeInt 32 1 |
| 1613 | %int_0 = OpConstant %int 0 |
| 1614 | %_arr__struct_24_uint_1_0 = OpTypeArray %_struct_24 %uint_1 |
| 1615 | %Src = OpTypeStruct %_arr__struct_24_uint_1_0 |
| 1616 | %_ptr_Uniform_Src = OpTypePointer Uniform %Src |
| 1617 | %src = OpVariable %_ptr_Uniform_Src Uniform |
| 1618 | %_ptr_Uniform__struct_24 = OpTypePointer Uniform %_struct_24 |
| 1619 | %main = OpFunction %void None %3 |
| 1620 | %5 = OpLabel |
| 1621 | %index = OpVariable %_ptr_Function_uint Function |
| 1622 | %14 = OpAccessChain %_ptr_Input_uint %gl_GlobalInvocationID %uint_4864 |
| 1623 | %15 = OpLoad %uint %14 |
| 1624 | OpStore %index %15 |
| 1625 | %16 = OpLoad %uint %index |
| 1626 | %S = OpUGreaterThanEqual %bool %16 %uint_1 |
| 1627 | OpSelectionMerge %21 None |
| 1628 | OpBranchConditional %S %20 %21 |
| 1629 | %20 = OpLabel |
| 1630 | OpReturn |
| 1631 | %21 = OpLabel |
| 1632 | %31 = OpLoad %uint %index |
| 1633 | %36 = OpLoad %uint %index |
| 1634 | %38 = OpAccessChain %_ptr_Uniform__struct_24 %src %int_0 %36 |
| 1635 | %39 = OpLoad %_struct_24 %38 |
| 1636 | %40 = OpAccessChain %_ptr_Uniform__struct_24 %dst %int_0 %31 |
| 1637 | OpStore %40 %39 |
| 1638 | OpReturn |
| 1639 | OpFunctionEnd |
| 1640 | )"; |
| 1641 | |
| 1642 | std::vector<uint32_t> optimized_bin; |
| 1643 | auto status = spvtools::opt::Pass::Status::Failure; |
| 1644 | std::tie(optimized_bin, status) = |
| 1645 | SinglePassRunToBinary<GraphicsRobustAccessPass>(shader, false); |
| 1646 | // Check whether the pass returns the correct modification indication. |
| 1647 | EXPECT_EQ(status, spvtools::opt::Pass::Status::SuccessWithChange); |
| 1648 | } |
| 1649 | |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 1650 | // TODO(dneto): Test access chain index wider than 64 bits? |
| 1651 | // TODO(dneto): Test struct access chain index wider than 64 bits? |
| 1652 | // TODO(dneto): OpImageTexelPointer |
| 1653 | // - all Dim types: 1D 2D Cube 3D Rect Buffer |
| 1654 | // - all Dim types that can be arrayed: 1D 2D 3D |
| 1655 | // - sample index: set to 0 if not multisampled |
| 1656 | // - Dim (2D, Cube Rect} with multisampling |
| 1657 | // -1 0 max excess |
| 1658 | // TODO(dneto): Test OpImageTexelPointer with coordinate component index other |
| 1659 | // than 32 bits. |
| 1660 | |
| 1661 | } // namespace |