blob: 057b909def8301c4cf3d20c6eae720e1593154ef [file] [log] [blame]
Ben Claytond0f684e2019-08-30 22:36:08 +01001// 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
25namespace {
26
27using namespace spvtools;
28
29using opt::GraphicsRobustAccessPass;
30using GraphicsRobustAccessTest = opt::PassTest<::testing::Test>;
31
32// Test incompatible module, determined at module-level.
33
34TEST_F(GraphicsRobustAccessTest, FailNotShader) {
35 const std::string text = R"(
36; CHECK: Can only process Shader modules
37OpCapability Kernel
38)";
39
40 SinglePassRunAndFail<GraphicsRobustAccessPass>(text);
41}
42
43TEST_F(GraphicsRobustAccessTest, FailCantProcessVariablePointers) {
44 const std::string text = R"(
45; CHECK: Can't process modules with VariablePointers capability
46OpCapability VariablePointers
47)";
48
49 SinglePassRunAndFail<GraphicsRobustAccessPass>(text);
50}
51
52TEST_F(GraphicsRobustAccessTest, FailCantProcessVariablePointersStorageBuffer) {
53 const std::string text = R"(
54; CHECK: Can't process modules with VariablePointersStorageBuffer capability
55OpCapability VariablePointersStorageBuffer
56)";
57
58 SinglePassRunAndFail<GraphicsRobustAccessPass>(text);
59}
60
61TEST_F(GraphicsRobustAccessTest, FailCantProcessRuntimeDescriptorArrayEXT) {
62 const std::string text = R"(
63; CHECK: Can't process modules with RuntimeDescriptorArrayEXT capability
64OpCapability RuntimeDescriptorArrayEXT
65)";
66
67 SinglePassRunAndFail<GraphicsRobustAccessPass>(text);
68}
69
70TEST_F(GraphicsRobustAccessTest, FailCantProcessPhysical32AddressingModel) {
71 const std::string text = R"(
72; CHECK: Addressing model must be Logical. Found OpMemoryModel Physical32 OpenCL
73OpCapability Shader
74OpMemoryModel Physical32 OpenCL
75)";
76
77 SinglePassRunAndFail<GraphicsRobustAccessPass>(text);
78}
79
80TEST_F(GraphicsRobustAccessTest, FailCantProcessPhysical64AddressingModel) {
81 const std::string text = R"(
82; CHECK: Addressing model must be Logical. Found OpMemoryModel Physical64 OpenCL
83OpCapability Shader
84OpMemoryModel Physical64 OpenCL
85)";
86
87 SinglePassRunAndFail<GraphicsRobustAccessPass>(text);
88}
89
90TEST_F(GraphicsRobustAccessTest,
91 FailCantProcessPhysicalStorageBuffer64EXTAddressingModel) {
92 const std::string text = R"(
Ben Claytond552f632019-11-18 11:18:41 +000093; CHECK: Addressing model must be Logical. Found OpMemoryModel PhysicalStorageBuffer64 GLSL450
Ben Claytond0f684e2019-08-30 22:36:08 +010094OpCapability Shader
95OpMemoryModel 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.)
106std::vector<const char*> AccessChains() {
107 return {"OpAccessChain", "OpInBoundsAccessChain"};
108}
109
110std::string ShaderPreamble() {
111 return R"(
112 OpCapability Shader
113 OpMemoryModel Logical Simple
114 OpEntryPoint GLCompute %main "main"
115)";
116}
117
118std::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
127std::string ShaderPreambleAC() {
128 return ShaderPreamble({"ac", "ptr_ty", "var"});
129}
130
131std::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
139std::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
150std::string TypesVoid() {
151 return R"(
152 %void = OpTypeVoid
153 %void_fn = OpTypeFunction %void
154)";
155}
156
157std::string TypesInt() {
158 return R"(
159 %uint = OpTypeInt 32 0
160 %int = OpTypeInt 32 1
161)";
162}
163
164std::string TypesFloat() {
165 return R"(
166 %float = OpTypeFloat 32
167)";
168}
169
170std::string TypesShort() {
171 return R"(
172 %ushort = OpTypeInt 16 0
173 %short = OpTypeInt 16 1
174)";
175}
176
177std::string TypesLong() {
178 return R"(
179 %ulong = OpTypeInt 64 0
180 %long = OpTypeInt 64 1
181)";
182}
183
184std::string MainPrefix() {
185 return R"(
186 %main = OpFunction %void None %void_fn
187 %entry = OpLabel
188)";
189}
190
191std::string MainSuffix() {
192 return R"(
193 OpReturn
194 OpFunctionEnd
195)";
196}
197
198std::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 Claytond552f632019-11-18 11:18:41 +0000202 (transformed.empty() ? "" : " ") + transformed +
Ben Claytond0f684e2019-08-30 22:36:08 +0100203 "\n ; CHECK-NOT: " + access_chain_inst +
204 "\n ; CHECK-NEXT: OpReturn"
205 "\n %ac = " +
Ben Claytond552f632019-11-18 11:18:41 +0000206 access_chain_inst + " %ptr_ty %var " + (original.empty() ? "" : " ") +
Ben Claytond0f684e2019-08-30 22:36:08 +0100207 original + "\n";
208}
209
210std::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 Claytond552f632019-11-18 11:18:41 +0000214 (transformed.empty() ? "" : " ") + transformed +
Ben Claytond0f684e2019-08-30 22:36:08 +0100215 "\n ; CHECK-NOT: " + access_chain_inst +
216 "\n ; CHECK-NOT: OpReturn"
217 "\n %ac = " +
Ben Claytond552f632019-11-18 11:18:41 +0000218 access_chain_inst + " %ptr_ty %var " + (original.empty() ? "" : " ") +
Ben Claytond0f684e2019-08-30 22:36:08 +0100219 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
232TEST_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
248TEST_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
264TEST_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 Clayton0b54f132020-01-06 13:38:54 +0000274 %var = OpVariable %var_ty Function)" << ACCheck(ac, "%uint_4", "%int_3")
Ben Claytond0f684e2019-08-30 22:36:08 +0100275 << MainSuffix();
276 SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
277 }
278}
279
280TEST_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.
299TEST_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
319TEST_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 Clayton0b54f132020-01-06 13:38:54 +0000332 ; CHECK: %[[clamp:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %i %int_0 %int_3
Ben Claytond0f684e2019-08-30 22:36:08 +0100333 %var = OpVariable %var_ty Function)" << ACCheck(ac, "%i", "%[[clamp]]")
334 << MainSuffix();
335 SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
336 }
337}
338
339TEST_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 Clayton0b54f132020-01-06 13:38:54 +0000357 ; CHECK: %[[clamp:\w+]] = OpExtInst %short %[[GLSLSTD450]] SClamp %i %short_0 %short_3
Ben Claytond0f684e2019-08-30 22:36:08 +0100358 %var = OpVariable %var_ty Function)" << ACCheck(ac, "%i", "%[[clamp]]")
359 << MainSuffix();
360 SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
361 }
362}
363
364TEST_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 Clayton0b54f132020-01-06 13:38:54 +0000378 ; CHECK-DAG: %short_0 = OpConstant %short 0
379 ; CHECK-DAG: %short_3 = OpConstant %short 3
Ben Claytond0f684e2019-08-30 22:36:08 +0100380 ; CHECK-NOT: = OpTypeInt 32
381 ; CHECK: OpLabel
Ben Clayton0b54f132020-01-06 13:38:54 +0000382 ; CHECK: %[[clamp:\w+]] = OpExtInst %ushort %[[GLSLSTD450]] SClamp %i %short_0 %short_3
Ben Claytond0f684e2019-08-30 22:36:08 +0100383 %var = OpVariable %var_ty Function)" << ACCheck(ac, "%i", "%[[clamp]]")
384 << MainSuffix();
385 SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
386 }
387}
388
389TEST_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 Clayton0b54f132020-01-06 13:38:54 +0000407 ; CHECK: %[[clamp:\w+]] = OpExtInst %long %[[GLSLSTD450]] SClamp %i %long_0 %long_3
Ben Claytond0f684e2019-08-30 22:36:08 +0100408 %var = OpVariable %var_ty Function)" << ACCheck(ac, "%i", "%[[clamp]]")
409 << MainSuffix();
410 SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
411 }
412}
413
414TEST_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 Clayton0b54f132020-01-06 13:38:54 +0000428 ; CHECK-DAG: %long_0 = OpConstant %long 0
429 ; CHECK-DAG: %long_3 = OpConstant %long 3
Ben Claytond0f684e2019-08-30 22:36:08 +0100430 ; CHECK-NOT: = OpTypeInt 32
431 ; CHECK: OpLabel
Ben Clayton0b54f132020-01-06 13:38:54 +0000432 ; CHECK: %[[clamp:\w+]] = OpExtInst %ulong %[[GLSLSTD450]] SClamp %i %long_0 %long_3
Ben Claytond0f684e2019-08-30 22:36:08 +0100433 %var = OpVariable %var_ty Function)" << ACCheck(ac, "%i", "%[[clamp]]")
434 << MainSuffix();
435 SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
436 }
437}
438
439TEST_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
458TEST_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
477TEST_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 Clayton0b54f132020-01-06 13:38:54 +0000489 ; CHECK: %int_3 = OpConstant %int 3
Ben Claytond0f684e2019-08-30 22:36:08 +0100490 %var = OpVariable %var_ty Function)"
Ben Clayton0b54f132020-01-06 13:38:54 +0000491 << ACCheck(ac, "%uint_4 %uint_1", "%int_3 %uint_1") << MainSuffix();
Ben Claytond0f684e2019-08-30 22:36:08 +0100492 SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
493 }
494}
495
496TEST_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
515TEST_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 Clayton0b54f132020-01-06 13:38:54 +0000531 ; CHECK: %[[clamp:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %i %int_0 %int_3
Ben Claytond0f684e2019-08-30 22:36:08 +0100532 %var = OpVariable %var_ty Function)"
533 << ACCheck(ac, "%i %uint_1", "%[[clamp]] %uint_1") << MainSuffix();
534 SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
535 }
536}
537
538TEST_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
555TEST_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
572TEST_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 Clayton0b54f132020-01-06 13:38:54 +0000587 ; CHECK: %[[clamp:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %i %int_0 %int_199
Ben Claytond0f684e2019-08-30 22:36:08 +0100588 %var = OpVariable %var_ty Function)"
589 << ACCheck(ac, "%i", "%[[clamp]]") << MainSuffix();
590 SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
591 }
592}
593
594TEST_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 Clayton0b54f132020-01-06 13:38:54 +0000608 ; CHECK-DAG: %int_0 = OpConstant %int 0
609 ; CHECK-DAG: %int_69999 = OpConstant %int 69999
Ben Claytond0f684e2019-08-30 22:36:08 +0100610 ; CHECK: OpLabel
611 ; CHECK: %[[i_ext:\w+]] = OpSConvert %uint %i
Ben Clayton0b54f132020-01-06 13:38:54 +0000612 ; CHECK: %[[clamp:\w+]] = OpExtInst %uint %[[GLSLSTD450]] SClamp %[[i_ext]] %int_0 %int_69999
Ben Claytond0f684e2019-08-30 22:36:08 +0100613 %var = OpVariable %var_ty Function)"
614 << ACCheck(ac, "%i", "%[[clamp]]") << MainSuffix();
615 SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
616 }
617}
618
619TEST_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 Clayton0b54f132020-01-06 13:38:54 +0000633 ; CHECK-DAG: %int_0 = OpConstant %int 0
634 ; CHECK-DAG: %int_69999 = OpConstant %int 69999
Ben Claytond0f684e2019-08-30 22:36:08 +0100635 ; CHECK: OpLabel
636 ; CHECK: %[[i_ext:\w+]] = OpUConvert %uint %i
Ben Clayton0b54f132020-01-06 13:38:54 +0000637 ; CHECK: %[[clamp:\w+]] = OpExtInst %uint %[[GLSLSTD450]] SClamp %[[i_ext]] %int_0 %int_69999
Ben Claytond0f684e2019-08-30 22:36:08 +0100638 %var = OpVariable %var_ty Function)"
639 << ACCheck(ac, "%i", "%[[clamp]]") << MainSuffix();
640 SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
641 }
642}
643
644TEST_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 Clayton0b54f132020-01-06 13:38:54 +0000658 ; CHECK-DAG: %int_0 = OpConstant %int 0
659 ; CHECK-DAG: %int_199 = OpConstant %int 199
Ben Claytond0f684e2019-08-30 22:36:08 +0100660 ; CHECK: OpLabel
Ben Clayton0b54f132020-01-06 13:38:54 +0000661 ; CHECK: %[[clamp:\w+]] = OpExtInst %uint %[[GLSLSTD450]] SClamp %i %int_0 %int_199
Ben Claytond0f684e2019-08-30 22:36:08 +0100662 %var = OpVariable %var_ty Function)"
663 << ACCheck(ac, "%i", "%[[clamp]]") << MainSuffix();
664 SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
665 }
666}
667
668TEST_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 Clayton0b54f132020-01-06 13:38:54 +0000685 ; CHECK: %[[clamp:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %i %int_0 %int_199
Ben Claytond0f684e2019-08-30 22:36:08 +0100686 %var = OpVariable %var_ty Function)"
687 << ACCheck(ac, "%i", "%[[clamp]]") << MainSuffix();
688 SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
689 }
690}
691
692TEST_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 Clayton0b54f132020-01-06 13:38:54 +0000709 ; CHECK: %[[clamp:\w+]] = OpExtInst %long %[[GLSLSTD450]] SClamp %i %long_0 %long_199
Ben Claytond0f684e2019-08-30 22:36:08 +0100710 %var = OpVariable %var_ty Function)"
711 << ACCheck(ac, "%i", "%[[clamp]]") << MainSuffix();
712 SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
713 }
714}
715
716TEST_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 Clayton0b54f132020-01-06 13:38:54 +0000730 ; CHECK-DAG: %long_0 = OpConstant %long 0
731 ; CHECK-DAG: %long_199 = OpConstant %long 199
Ben Claytond0f684e2019-08-30 22:36:08 +0100732 ; CHECK: OpLabel
Ben Clayton0b54f132020-01-06 13:38:54 +0000733 ; CHECK: %[[clamp:\w+]] = OpExtInst %ulong %[[GLSLSTD450]] SClamp %i %long_0 %long_199
Ben Claytond0f684e2019-08-30 22:36:08 +0100734 %var = OpVariable %var_ty Function)"
735 << ACCheck(ac, "%i", "%[[clamp]]") << MainSuffix();
736 SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
737 }
738}
739
Ben Clayton0b54f132020-01-06 13:38:54 +0000740TEST_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
764TEST_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
787TEST_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 Claytond0f684e2019-08-30 22:36:08 +0100815TEST_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 Clayton0b54f132020-01-06 13:38:54 +0000830 ; CHECK-DAG: %[[uint_intmax:\w+]] = OpConstant %uint 2147483647
Ben Claytond0f684e2019-08-30 22:36:08 +0100831 ; CHECK: OpLabel
832 ; CHECK: %[[max:\w+]] = OpISub %uint %spec200 %uint_1
Ben Clayton0b54f132020-01-06 13:38:54 +0000833 ; CHECK: %[[smin:\w+]] = OpExtInst %uint %[[GLSLSTD450]] UMin %[[max]] %[[uint_intmax]]
834 ; CHECK: %[[clamp:\w+]] = OpExtInst %uint %[[GLSLSTD450]] SClamp %uint_5 %uint_0 %[[smin]]
Ben Claytond0f684e2019-08-30 22:36:08 +0100835 %var = OpVariable %var_ty Function)"
836 << ACCheck(ac, "%uint_5", "%[[clamp]]") << MainSuffix();
837 SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
838 }
839}
840
841TEST_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
857TEST_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
873TEST_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
895TEST_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
915TEST_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
936TEST_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
955TEST_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
974TEST_F(GraphicsRobustAccessTest, ACRTArrayLeastInboundClamped) {
975 for (auto* ac : AccessChains()) {
976 std::ostringstream shaders;
Ben Claytond552f632019-11-18 11:18:41 +0000977 shaders << ShaderPreambleAC() << "OpDecorate %rtarr ArrayStride 4 "
Ben Claytond0f684e2019-08-30 22:36:08 +0100978 << 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 Clayton0b54f132020-01-06 13:38:54 +0000987 ; CHECK-DAG: %int_1 = OpConstant %int 1
988 ; CHECK-DAG: %[[intmax:\w+]] = OpConstant %int 2147483647
Ben Claytond0f684e2019-08-30 22:36:08 +0100989 ; CHECK: OpLabel
990 ; CHECK: %[[arrlen:\w+]] = OpArrayLength %uint %var 2
991 ; CHECK: %[[max:\w+]] = OpISub %int %[[arrlen]] %int_1
Ben Clayton0b54f132020-01-06 13:38:54 +0000992 ; CHECK: %[[smin:\w+]] = OpExtInst %int %[[GLSLSTD450]] UMin %[[max]] %[[intmax]]
993 ; CHECK: %[[clamp:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %int_0 %int_0 %[[smin]]
Ben Claytond0f684e2019-08-30 22:36:08 +0100994 )"
995 << MainPrefix() << ACCheck(ac, "%int_2 %int_0", "%int_2 %[[clamp]]")
996 << MainSuffix();
997 SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
998 }
999}
1000
1001TEST_F(GraphicsRobustAccessTest, ACRTArrayGeneralShortIndexClamped) {
1002 for (auto* ac : AccessChains()) {
1003 std::ostringstream shaders;
1004 shaders << "OpCapability Int16\n"
Ben Claytond552f632019-11-18 11:18:41 +00001005 << ShaderPreambleAC({"i"}) << "OpDecorate %rtarr ArrayStride 4 "
1006 << DecoSSBO() << TypesVoid() << TypesShort() << TypesFloat() << R"(
Ben Claytond0f684e2019-08-30 22:36:08 +01001007 %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 Clayton0b54f132020-01-06 13:38:54 +00001018 ; CHECK-DAG: %[[intmax:\w+]] = OpConstant %uint 2147483647
Ben Claytond0f684e2019-08-30 22:36:08 +01001019 ; 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 Clayton0b54f132020-01-06 13:38:54 +00001023 ; CHECK: %[[smin:\w+]] = OpExtInst %uint %[[GLSLSTD450]] UMin %[[max]] %[[intmax]]
1024 ; CHECK: %[[clamp:\w+]] = OpExtInst %uint %[[GLSLSTD450]] SClamp %[[i_ext]] %uint_0 %[[smin]]
Ben Claytond0f684e2019-08-30 22:36:08 +01001025 )"
1026 << MainPrefix() << ACCheck(ac, "%short_2 %i", "%short_2 %[[clamp]]")
1027 << MainSuffix();
1028 SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
1029 }
1030}
1031
1032TEST_F(GraphicsRobustAccessTest, ACRTArrayGeneralUShortIndexClamped) {
1033 for (auto* ac : AccessChains()) {
1034 std::ostringstream shaders;
1035 shaders << "OpCapability Int16\n"
Ben Claytond552f632019-11-18 11:18:41 +00001036 << ShaderPreambleAC({"i"}) << "OpDecorate %rtarr ArrayStride 4 "
1037 << DecoSSBO() << TypesVoid() << TypesShort() << TypesFloat() << R"(
Ben Claytond0f684e2019-08-30 22:36:08 +01001038 %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 Clayton0b54f132020-01-06 13:38:54 +00001049 ; CHECK-DAG: %[[intmax:\w+]] = OpConstant %uint 2147483647
Ben Claytond0f684e2019-08-30 22:36:08 +01001050 ; 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 Clayton0b54f132020-01-06 13:38:54 +00001054 ; CHECK: %[[smin:\w+]] = OpExtInst %uint %[[GLSLSTD450]] UMin %[[max]] %[[intmax]]
1055 ; CHECK: %[[clamp:\w+]] = OpExtInst %uint %[[GLSLSTD450]] SClamp %[[i_ext]] %uint_0 %[[smin]]
Ben Claytond0f684e2019-08-30 22:36:08 +01001056 )"
1057 << MainPrefix() << ACCheck(ac, "%short_2 %i", "%short_2 %[[clamp]]")
1058 << MainSuffix();
1059 SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
1060 }
1061}
1062
1063TEST_F(GraphicsRobustAccessTest, ACRTArrayGeneralIntIndexClamped) {
1064 for (auto* ac : AccessChains()) {
1065 std::ostringstream shaders;
Ben Claytond552f632019-11-18 11:18:41 +00001066 shaders << ShaderPreambleAC({"i"}) << "OpDecorate %rtarr ArrayStride 4 "
1067 << DecoSSBO() << TypesVoid() << TypesInt() << TypesFloat() << R"(
Ben Claytond0f684e2019-08-30 22:36:08 +01001068 %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 Clayton0b54f132020-01-06 13:38:54 +00001078 ; CHECK-DAG: %[[intmax:\w+]] = OpConstant %int 2147483647
Ben Claytond0f684e2019-08-30 22:36:08 +01001079 ; CHECK: OpLabel
1080 ; CHECK: %[[arrlen:\w+]] = OpArrayLength %uint %var 2
1081 ; CHECK: %[[max:\w+]] = OpISub %int %[[arrlen]] %int_1
Ben Clayton0b54f132020-01-06 13:38:54 +00001082 ; CHECK: %[[smin:\w+]] = OpExtInst %int %[[GLSLSTD450]] UMin %[[max]] %[[intmax]]
1083 ; CHECK: %[[clamp:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %i %int_0 %[[smin]]
Ben Claytond552f632019-11-18 11:18:41 +00001084 )"
1085 << MainPrefix() << ACCheck(ac, "%int_2 %i", "%int_2 %[[clamp]]")
1086 << MainSuffix();
Ben Claytond0f684e2019-08-30 22:36:08 +01001087 SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
1088 }
1089}
1090
1091TEST_F(GraphicsRobustAccessTest, ACRTArrayGeneralUIntIndexClamped) {
1092 for (auto* ac : AccessChains()) {
1093 std::ostringstream shaders;
Ben Claytond552f632019-11-18 11:18:41 +00001094 shaders << ShaderPreambleAC({"i"}) << "OpDecorate %rtarr ArrayStride 4 "
1095 << DecoSSBO() << TypesVoid() << TypesInt() << TypesFloat() << R"(
Ben Claytond0f684e2019-08-30 22:36:08 +01001096 %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 Clayton0b54f132020-01-06 13:38:54 +00001106 ; CHECK-DAG: %[[intmax:\w+]] = OpConstant %uint 2147483647
Ben Claytond0f684e2019-08-30 22:36:08 +01001107 ; CHECK: OpLabel
1108 ; CHECK: %[[arrlen:\w+]] = OpArrayLength %uint %var 2
1109 ; CHECK: %[[max:\w+]] = OpISub %uint %[[arrlen]] %uint_1
Ben Clayton0b54f132020-01-06 13:38:54 +00001110 ; CHECK: %[[smin:\w+]] = OpExtInst %uint %[[GLSLSTD450]] UMin %[[max]] %[[intmax]]
1111 ; CHECK: %[[clamp:\w+]] = OpExtInst %uint %[[GLSLSTD450]] SClamp %i %uint_0 %[[smin]]
Ben Claytond552f632019-11-18 11:18:41 +00001112 )"
1113 << MainPrefix() << ACCheck(ac, "%int_2 %i", "%int_2 %[[clamp]]")
1114 << MainSuffix();
Ben Claytond0f684e2019-08-30 22:36:08 +01001115 SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
1116 }
1117}
1118
1119TEST_F(GraphicsRobustAccessTest, ACRTArrayGeneralLongIndexClamped) {
1120 for (auto* ac : AccessChains()) {
1121 std::ostringstream shaders;
1122 shaders << "OpCapability Int64" << ShaderPreambleAC({"i"})
Ben Claytond552f632019-11-18 11:18:41 +00001123 << "OpDecorate %rtarr ArrayStride 4 " << DecoSSBO() << TypesVoid()
1124 << TypesInt() << TypesLong() << TypesFloat() << R"(
Ben Claytond0f684e2019-08-30 22:36:08 +01001125 %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 Clayton0b54f132020-01-06 13:38:54 +00001135 ; CHECK-DAG: %[[longmax:\w+]] = OpConstant %long 9223372036854775807
Ben Claytond0f684e2019-08-30 22:36:08 +01001136 ; 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 Clayton0b54f132020-01-06 13:38:54 +00001140 ; CHECK: %[[smin:\w+]] = OpExtInst %long %[[GLSLSTD450]] UMin %[[max]] %[[longmax]]
1141 ; CHECK: %[[clamp:\w+]] = OpExtInst %long %[[GLSLSTD450]] SClamp %i %long_0 %[[smin]]
Ben Claytond552f632019-11-18 11:18:41 +00001142 )" << MainPrefix()
1143 << ACCheck(ac, "%int_2 %i", "%int_2 %[[clamp]]") << MainSuffix();
Ben Claytond0f684e2019-08-30 22:36:08 +01001144 SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
1145 }
1146}
1147
1148TEST_F(GraphicsRobustAccessTest, ACRTArrayGeneralULongIndexClamped) {
1149 for (auto* ac : AccessChains()) {
1150 std::ostringstream shaders;
1151 shaders << "OpCapability Int64" << ShaderPreambleAC({"i"})
Ben Claytond552f632019-11-18 11:18:41 +00001152 << "OpDecorate %rtarr ArrayStride 4 " << DecoSSBO() << TypesVoid()
1153 << TypesInt() << TypesLong() << TypesFloat() << R"(
Ben Claytond0f684e2019-08-30 22:36:08 +01001154 %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 Clayton0b54f132020-01-06 13:38:54 +00001164 ; CHECK-DAG: %[[longmax:\w+]] = OpConstant %ulong 9223372036854775807
Ben Claytond0f684e2019-08-30 22:36:08 +01001165 ; 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 Clayton0b54f132020-01-06 13:38:54 +00001169 ; CHECK: %[[smin:\w+]] = OpExtInst %ulong %[[GLSLSTD450]] UMin %[[max]] %[[longmax]]
1170 ; CHECK: %[[clamp:\w+]] = OpExtInst %ulong %[[GLSLSTD450]] SClamp %i %ulong_0 %[[smin]]
Ben Claytond552f632019-11-18 11:18:41 +00001171 )" << MainPrefix()
1172 << ACCheck(ac, "%int_2 %i", "%int_2 %[[clamp]]") << MainSuffix();
Ben Claytond0f684e2019-08-30 22:36:08 +01001173 SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
1174 }
1175}
1176
1177TEST_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 Claytond552f632019-11-18 11:18:41 +00001184 << "OpDecorate %rtarr ArrayStride 32\n"
Ben Claytond0f684e2019-08-30 22:36:08 +01001185 << 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 Clayton0b54f132020-01-06 13:38:54 +00001202 ; CHECK-DAG: %[[intmax:\w+]] = OpConstant %int 2147483647
Ben Claytond0f684e2019-08-30 22:36:08 +01001203 ; CHECK: OpLabel
1204 ; CHECK: %[[arrlen:\w+]] = OpArrayLength %uint %var 2
1205 ; CHECK: %[[max:\w+]] = OpISub %int %[[arrlen]] %int_1
Ben Clayton0b54f132020-01-06 13:38:54 +00001206 ; 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 Claytond0f684e2019-08-30 22:36:08 +01001209 )" << 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
1217TEST_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 Claytond552f632019-11-18 11:18:41 +00001222 << "OpDecorate %rtarr ArrayStride 32\n"
Ben Claytond0f684e2019-08-30 22:36:08 +01001223 << 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 Clayton0b54f132020-01-06 13:38:54 +00001243 ; CHECK-DAG: %[[intmax:\w+]] = OpConstant %int 2147483647
Ben Claytond0f684e2019-08-30 22:36:08 +01001244 ; CHECK: OpLabel
sugoi1b398bf32022-02-18 10:27:28 -05001245 ; This access chain is manufactured only so we can compute the array length.
Ben Claytond0f684e2019-08-30 22:36:08 +01001246 ; 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 Clayton0b54f132020-01-06 13:38:54 +00001251 ; CHECK: %[[smin:\w+]] = OpExtInst %int %[[GLSLSTD450]] UMin %[[max]] %[[intmax]]
1252 ; CHECK: %[[clamp_i:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %i %int_0 %[[smin]]
Ben Claytond0f684e2019-08-30 22:36:08 +01001253 )" << 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
1261TEST_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 Claytond552f632019-11-18 11:18:41 +00001268 << "OpDecorate %rtarr ArrayStride 32\n"
Ben Claytond0f684e2019-08-30 22:36:08 +01001269 << 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 Clayton0b54f132020-01-06 13:38:54 +00001292 ; CHECK-DAG: %[[intmax:\w+]] = OpConstant %int 2147483647
Ben Claytond0f684e2019-08-30 22:36:08 +01001293 ; CHECK: OpLabel
Ben Clayton0b54f132020-01-06 13:38:54 +00001294 ; CHECK: %[[clamp_i:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %i %int_0 %int_9
Ben Claytond0f684e2019-08-30 22:36:08 +01001295 ; 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 Clayton0b54f132020-01-06 13:38:54 +00001305 ; 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 Claytond0f684e2019-08-30 22:36:08 +01001308 ; 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
1321TEST_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 Hetu3eb4dd82020-10-29 21:37:20 -04001326 // This is an integrity check to ensure that we keep the instruction-to-block
1327 // mapping consistent.
Ben Claytond0f684e2019-08-30 22:36:08 +01001328 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 Claytond552f632019-11-18 11:18:41 +00001333 << "OpDecorate %rtarr ArrayStride 32\n"
Ben Claytond0f684e2019-08-30 22:36:08 +01001334 << 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 Clayton0b54f132020-01-06 13:38:54 +00001357 ; CHECK-DAG: %[[intmax:\w+]] = OpConstant %int 2147483647
Ben Claytond0f684e2019-08-30 22:36:08 +01001358 ; CHECK: OpLabel
Ben Clayton0b54f132020-01-06 13:38:54 +00001359 ; CHECK: %[[clamp_i:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %i %int_0 %int_9
Ben Claytond0f684e2019-08-30 22:36:08 +01001360 ; 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 Clayton0b54f132020-01-06 13:38:54 +00001372 ; 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 Claytond0f684e2019-08-30 22:36:08 +01001375 ; 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 Hetu3eb4dd82020-10-29 21:37:20 -04001390TEST_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"
1476OpMemoryModel Logical GLSL450
1477OpEntryPoint Fragment %main "main" %texCoord %fragColor
1478OpExecutionMode %main OriginUpperLeft
1479OpSource GLSL 450
1480OpSourceExtension "GL_GOOGLE_cpp_style_line_directive"
1481OpSourceExtension "GL_GOOGLE_include_directive"
1482OpName %main "main"
1483OpName %sc "sc"
1484OpName %texCoord "texCoord"
1485OpName %tc "tc"
1486OpName %fragColor "fragColor"
1487OpName %texture0 "texture0"
1488OpName %sampler0 "sampler0"
1489OpDecorate %texCoord Location 0
1490OpDecorate %fragColor Location 0
1491OpDecorate %texture0 DescriptorSet 0
1492OpDecorate %texture0 Binding 1
1493OpDecorate %sampler0 DescriptorSet 0
1494OpDecorate %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
1528OpStore %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
1533OpStore %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
1542OpStore %fragColor %45
1543OpReturn
1544OpFunctionEnd
1545)";
1546
1547 SinglePassRunAndCheck<GraphicsRobustAccessPass>(shader, expected, false,
1548 true);
1549}
1550
Alexis Hetu00e0af12021-11-08 08:57:46 -05001551TEST_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 Claytond0f684e2019-08-30 22:36:08 +01001650// 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