Create a pass to work around a driver bug related to OpUnreachable.
authorSteven Perron <stevenperron@google.com>
Wed, 17 Jan 2018 19:57:37 +0000 (14:57 -0500)
committerSteven Perron <stevenperron@google.com>
Fri, 19 Jan 2018 01:31:46 +0000 (20:31 -0500)
We have come across a driver bug where and OpUnreachable inside a loop
is causing the shader to go into an infinite loop.  This commit will try
to avoid this bug by turning OpUnreachable instructions that are
contained in a loop into branches to the loop merge block.

This is not added to "-O" and "-Os" because it should only be used if
the driver being targeted has this problem.

Fixes #1209.

Android.mk
include/spirv-tools/optimizer.hpp
source/opt/CMakeLists.txt
source/opt/optimizer.cpp
source/opt/passes.h
source/opt/workaround1209.cpp [new file with mode: 0644]
source/opt/workaround1209.h [new file with mode: 0644]
test/opt/CMakeLists.txt
test/opt/workaround1209_test.cpp [new file with mode: 0644]
tools/opt/opt.cpp

index 2aeae42..70d3bb6 100644 (file)
@@ -108,7 +108,8 @@ SPVTOOLS_OPT_SRC_FILES := \
                source/opt/type_manager.cpp \
                source/opt/types.cpp \
                source/opt/unify_const_pass.cpp \
-               source/opt/value_number_table.cpp
+               source/opt/value_number_table.cpp \
+               source/opt/workaround1209.cpp
 
 # Locations of grammar files.
 SPV_CORE10_GRAMMAR=$(SPVHEADERS_LOCAL_PATH)/include/spirv/1.0/spirv.core.grammar.json
index e1aac11..d1679ab 100644 (file)
@@ -475,6 +475,13 @@ Optimizer::PassToken CreatePrivateToLocalPass();
 // and computations with constant operands.
 Optimizer::PassToken CreateCCPPass();
 
+// Creates a workaround driver bugs pass.  This pass attempts to work around
+// a known driver bug (issue #1209) by identifying the bad code sequences and
+// rewriting them.
+//
+// Current workaround: Avoid OpUnreachable instructions in loops.
+Optimizer::PassToken CreateWorkaround1209Pass();
+
 }  // namespace spvtools
 
 #endif  // SPIRV_TOOLS_OPTIMIZER_HPP_
index 680edaf..8b2c584 100644 (file)
@@ -71,6 +71,7 @@ add_library(SPIRV-Tools-opt
   types.h
   unify_const_pass.h
   value_number_table.h
+  workaround1209.h
 
   aggressive_dead_code_elim_pass.cpp
   basic_block.cpp
@@ -127,6 +128,7 @@ add_library(SPIRV-Tools-opt
   types.cpp
   unify_const_pass.cpp
   value_number_table.cpp
+  workaround1209.cpp
 )
 
 spvtools_default_compile_options(SPIRV-Tools-opt)
index b85a8d8..f9f02d1 100644 (file)
@@ -349,4 +349,9 @@ Optimizer::PassToken CreateCCPPass() {
   return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::CCPPass>());
 }
 
+Optimizer::PassToken CreateWorkaround1209Pass() {
+  return MakeUnique<Optimizer::PassToken::Impl>(
+      MakeUnique<opt::Workaround1209>());
+}
+
 }  // namespace spvtools
index 1b1acdf..523db86 100644 (file)
@@ -48,5 +48,6 @@
 #include "strength_reduction_pass.h"
 #include "strip_debug_info_pass.h"
 #include "unify_const_pass.h"
+#include "workaround1209.h"
 
 #endif  // LIBSPIRV_OPT_PASSES_H_
diff --git a/source/opt/workaround1209.cpp b/source/opt/workaround1209.cpp
new file mode 100644 (file)
index 0000000..ae05848
--- /dev/null
@@ -0,0 +1,68 @@
+// Copyright (c) 2018 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "workaround1209.h"
+
+#include <list>
+#include <stack>
+
+namespace spvtools {
+namespace opt {
+
+Pass::Status Workaround1209::Process(ir::IRContext* c) {
+  InitializeProcessing(c);
+  bool modified = false;
+  modified = RemoveOpUnreachableInLoops();
+  return (modified ? Status::SuccessWithChange : Status::SuccessWithoutChange);
+}
+
+bool Workaround1209::RemoveOpUnreachableInLoops() {
+  bool modified = false;
+  for (auto& func : *get_module()) {
+    std::list<ir::BasicBlock*> structured_order;
+    cfg()->ComputeStructuredOrder(&func, &*func.begin(), &structured_order);
+
+    // Keep track of the loop merges.  The top of the stack will always be the
+    // loop merge for the loop that immediately contains the basic block being
+    // processed.
+    std::stack<uint32_t> loop_merges;
+    for (ir::BasicBlock* bb : structured_order) {
+      if (!loop_merges.empty() && bb->id() == loop_merges.top()) {
+        loop_merges.pop();
+      }
+
+      if (bb->tail()->opcode() == SpvOpUnreachable) {
+        if (!loop_merges.empty()) {
+          // We found an OpUnreachable inside a loop.
+          // Replace it with an unconditional branch to the loop merge.
+          context()->KillInst(&*bb->tail());
+          std::unique_ptr<ir::Instruction> new_branch(
+              new ir::Instruction(context(), SpvOpBranch, 0, 0,
+                                  {{spv_operand_type_t::SPV_OPERAND_TYPE_ID,
+                                    {loop_merges.top()}}}));
+          context()->AnalyzeDefUse(&*new_branch);
+          bb->AddInstruction(std::move(new_branch));
+          modified = true;
+        }
+      } else {
+        if (bb->GetLoopMergeInst()) {
+          loop_merges.push(bb->MergeBlockIdIfAny());
+        }
+      }
+    }
+  }
+  return modified;
+}
+}  // namespace opt
+}  // namespace spvtools
diff --git a/source/opt/workaround1209.h b/source/opt/workaround1209.h
new file mode 100644 (file)
index 0000000..2265ac3
--- /dev/null
@@ -0,0 +1,41 @@
+// Copyright (c) 2018 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef LIBSPIRV_OPT_WORKAROUND1209_H_
+#define LIBSPIRV_OPT_WORKAROUND1209_H_
+
+#include "pass.h"
+
+namespace spvtools {
+namespace opt {
+
+// See optimizer.hpp for documentation.
+class Workaround1209 : public Pass {
+ public:
+  const char* name() const override { return "workaround-1209"; }
+  Status Process(ir::IRContext*) override;
+
+ private:
+  // There is at least one driver where an OpUnreachable found in a loop is not
+  // handled correctly.  Workaround that by changing the OpUnreachable into a
+  // branch to the loop merge.
+  //
+  // Returns true if the code changed.
+  bool RemoveOpUnreachableInLoops();
+};
+
+}  // namespace opt
+}  // namespace spvtools
+
+#endif  // LIBSPIRV_OPT_WORKAROUND1209_H_
index bd83f94..04834bd 100644 (file)
@@ -261,3 +261,8 @@ add_spvtools_unittest(TARGET ccp
   SRCS ccp_test.cpp
   LIBS SPIRV-Tools-opt
 )
+
+add_spvtools_unittest(TARGET pass_workaround1209
+  SRCS workaround1209_test.cpp pass_utils.cpp
+  LIBS SPIRV-Tools-opt
+)
diff --git a/test/opt/workaround1209_test.cpp b/test/opt/workaround1209_test.cpp
new file mode 100644 (file)
index 0000000..5708b7e
--- /dev/null
@@ -0,0 +1,421 @@
+// Copyright (c) 2017 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "assembly_builder.h"
+#include "gmock/gmock.h"
+#include "pass_fixture.h"
+#include "pass_utils.h"
+
+#include <algorithm>
+#include <cstdarg>
+#include <iostream>
+#include <sstream>
+#include <unordered_set>
+
+namespace {
+
+using namespace spvtools;
+
+using Workaround1209Test = PassTest<::testing::Test>;
+
+#ifdef SPIRV_EFFCEE
+TEST_F(Workaround1209Test, RemoveOpUnreachableInLoop) {
+  const std::string text = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Vertex %main "main" %texcoord %gl_VertexIndex %_
+               OpSource GLSL 400
+               OpSourceExtension "GL_ARB_separate_shader_objects"
+               OpSourceExtension "GL_ARB_shading_language_420pack"
+               OpName %main "main"
+               OpName %texcoord "texcoord"
+               OpName %buf "buf"
+               OpMemberName %buf 0 "MVP"
+               OpMemberName %buf 1 "position"
+               OpMemberName %buf 2 "attr"
+               OpName %ubuf "ubuf"
+               OpName %gl_VertexIndex "gl_VertexIndex"
+               OpName %gl_PerVertex "gl_PerVertex"
+               OpMemberName %gl_PerVertex 0 "gl_Position"
+               OpName %_ ""
+               OpDecorate %texcoord Location 0
+               OpDecorate %_arr_v4float_uint_72 ArrayStride 16
+               OpDecorate %_arr_v4float_uint_72_0 ArrayStride 16
+               OpMemberDecorate %buf 0 ColMajor
+               OpMemberDecorate %buf 0 Offset 0
+               OpMemberDecorate %buf 0 MatrixStride 16
+               OpMemberDecorate %buf 1 Offset 64
+               OpMemberDecorate %buf 2 Offset 1216
+               OpDecorate %buf Block
+               OpDecorate %ubuf DescriptorSet 0
+               OpDecorate %ubuf Binding 0
+               OpDecorate %gl_VertexIndex BuiltIn VertexIndex
+               OpMemberDecorate %gl_PerVertex 0 BuiltIn Position
+               OpDecorate %gl_PerVertex Block
+       %void = OpTypeVoid
+         %12 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+   %texcoord = OpVariable %_ptr_Output_v4float Output
+%mat4v4float = OpTypeMatrix %v4float 4
+       %uint = OpTypeInt 32 0
+    %uint_72 = OpConstant %uint 72
+%_arr_v4float_uint_72 = OpTypeArray %v4float %uint_72
+%_arr_v4float_uint_72_0 = OpTypeArray %v4float %uint_72
+        %buf = OpTypeStruct %mat4v4float %_arr_v4float_uint_72 %_arr_v4float_uint_72_0
+%_ptr_Uniform_buf = OpTypePointer Uniform %buf
+       %ubuf = OpVariable %_ptr_Uniform_buf Uniform
+        %int = OpTypeInt 32 1
+      %int_2 = OpConstant %int 2
+%_ptr_Input_int = OpTypePointer Input %int
+%gl_VertexIndex = OpVariable %_ptr_Input_int Input
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+%gl_PerVertex = OpTypeStruct %v4float
+%_ptr_Output_gl_PerVertex = OpTypePointer Output %gl_PerVertex
+          %_ = OpVariable %_ptr_Output_gl_PerVertex Output
+      %int_0 = OpConstant %int 0
+      %int_1 = OpConstant %int 1
+    %float_1 = OpConstant %float 1
+         %28 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
+       %main = OpFunction %void None %12
+         %29 = OpLabel
+               OpBranch %30
+         %30 = OpLabel
+; CHECK: OpLoopMerge [[merge:%[a-zA-Z_\d]+]]
+               OpLoopMerge %31 %32 None
+               OpBranch %33
+         %33 = OpLabel
+; CHECK: OpSelectionMerge [[sel_merge:%[a-zA-Z_\d]+]]
+               OpSelectionMerge %34 None
+               OpSwitch %int_1 %35
+         %35 = OpLabel
+         %36 = OpLoad %int %gl_VertexIndex
+         %37 = OpAccessChain %_ptr_Uniform_v4float %ubuf %int_2 %36
+         %38 = OpLoad %v4float %37
+               OpStore %texcoord %38
+         %39 = OpAccessChain %_ptr_Output_v4float %_ %int_0
+               OpStore %39 %28
+               OpBranch %31
+; CHECK: [[sel_merge]] = OpLabel
+         %34 = OpLabel
+; CHECK-NEXT: OpBranch [[merge]]
+               OpUnreachable
+         %32 = OpLabel
+               OpBranch %30
+         %31 = OpLabel
+               OpReturn
+               OpFunctionEnd)";
+
+  SinglePassRunAndMatch<opt::Workaround1209>(text, false);
+}
+
+TEST_F(Workaround1209Test, RemoveOpUnreachableInNestedLoop) {
+  const std::string text = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Vertex %2 "main" %3 %4 %5
+               OpSource GLSL 400
+               OpSourceExtension "GL_ARB_separate_shader_objects"
+               OpSourceExtension "GL_ARB_shading_language_420pack"
+               OpName %2 "main"
+               OpName %3 "texcoord"
+               OpName %6 "buf"
+               OpMemberName %6 0 "MVP"
+               OpMemberName %6 1 "position"
+               OpMemberName %6 2 "attr"
+               OpName %7 "ubuf"
+               OpName %4 "gl_VertexIndex"
+               OpName %8 "gl_PerVertex"
+               OpMemberName %8 0 "gl_Position"
+               OpName %5 ""
+               OpDecorate %3 Location 0
+               OpDecorate %9 ArrayStride 16
+               OpDecorate %10 ArrayStride 16
+               OpMemberDecorate %6 0 ColMajor
+               OpMemberDecorate %6 0 Offset 0
+               OpMemberDecorate %6 0 MatrixStride 16
+               OpMemberDecorate %6 1 Offset 64
+               OpMemberDecorate %6 2 Offset 1216
+               OpDecorate %6 Block
+               OpDecorate %7 DescriptorSet 0
+               OpDecorate %7 Binding 0
+               OpDecorate %4 BuiltIn VertexIndex
+               OpMemberDecorate %8 0 BuiltIn Position
+               OpDecorate %8 Block
+         %11 = OpTypeVoid
+         %12 = OpTypeFunction %11
+         %13 = OpTypeFloat 32
+         %14 = OpTypeVector %13 4
+         %15 = OpTypePointer Output %14
+          %3 = OpVariable %15 Output
+         %16 = OpTypeMatrix %14 4
+         %17 = OpTypeInt 32 0
+         %18 = OpConstant %17 72
+          %9 = OpTypeArray %14 %18
+         %10 = OpTypeArray %14 %18
+          %6 = OpTypeStruct %16 %9 %10
+         %19 = OpTypePointer Uniform %6
+          %7 = OpVariable %19 Uniform
+         %20 = OpTypeInt 32 1
+         %21 = OpConstant %20 2
+         %22 = OpTypePointer Input %20
+          %4 = OpVariable %22 Input
+         %23 = OpTypePointer Uniform %14
+          %8 = OpTypeStruct %14
+         %24 = OpTypePointer Output %8
+          %5 = OpVariable %24 Output
+         %25 = OpConstant %20 0
+         %26 = OpConstant %20 1
+         %27 = OpConstant %13 1
+         %28 = OpConstantComposite %14 %27 %27 %27 %27
+          %2 = OpFunction %11 None %12
+         %29 = OpLabel
+               OpBranch %31
+         %31 = OpLabel
+; CHECK: OpLoopMerge
+               OpLoopMerge %32 %33 None
+               OpBranch %30
+         %30 = OpLabel
+; CHECK: OpLoopMerge [[merge:%[a-zA-Z_\d]+]]
+               OpLoopMerge %34 %35 None
+               OpBranch %36
+         %36 = OpLabel
+; CHECK: OpSelectionMerge [[sel_merge:%[a-zA-Z_\d]+]]
+               OpSelectionMerge %37 None
+               OpSwitch %26 %38
+         %38 = OpLabel
+         %39 = OpLoad %20 %4
+         %40 = OpAccessChain %23 %7 %21 %39
+         %41 = OpLoad %14 %40
+               OpStore %3 %41
+         %42 = OpAccessChain %15 %5 %25
+               OpStore %42 %28
+               OpBranch %34
+; CHECK: [[sel_merge]] = OpLabel
+         %37 = OpLabel
+; CHECK-NEXT: OpBranch [[merge]]
+               OpUnreachable
+         %35 = OpLabel
+               OpBranch %30
+         %34 = OpLabel
+               OpBranch %32
+         %33 = OpLabel
+               OpBranch %31
+         %32 = OpLabel
+               OpReturn
+               OpFunctionEnd)";
+
+  SinglePassRunAndMatch<opt::Workaround1209>(text, false);
+}
+
+TEST_F(Workaround1209Test, RemoveOpUnreachableInAdjacentLoops) {
+  const std::string text = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Vertex %2 "main" %3 %4 %5
+               OpSource GLSL 400
+               OpSourceExtension "GL_ARB_separate_shader_objects"
+               OpSourceExtension "GL_ARB_shading_language_420pack"
+               OpName %2 "main"
+               OpName %3 "texcoord"
+               OpName %6 "buf"
+               OpMemberName %6 0 "MVP"
+               OpMemberName %6 1 "position"
+               OpMemberName %6 2 "attr"
+               OpName %7 "ubuf"
+               OpName %4 "gl_VertexIndex"
+               OpName %8 "gl_PerVertex"
+               OpMemberName %8 0 "gl_Position"
+               OpName %5 ""
+               OpDecorate %3 Location 0
+               OpDecorate %9 ArrayStride 16
+               OpDecorate %10 ArrayStride 16
+               OpMemberDecorate %6 0 ColMajor
+               OpMemberDecorate %6 0 Offset 0
+               OpMemberDecorate %6 0 MatrixStride 16
+               OpMemberDecorate %6 1 Offset 64
+               OpMemberDecorate %6 2 Offset 1216
+               OpDecorate %6 Block
+               OpDecorate %7 DescriptorSet 0
+               OpDecorate %7 Binding 0
+               OpDecorate %4 BuiltIn VertexIndex
+               OpMemberDecorate %8 0 BuiltIn Position
+               OpDecorate %8 Block
+         %11 = OpTypeVoid
+         %12 = OpTypeFunction %11
+         %13 = OpTypeFloat 32
+         %14 = OpTypeVector %13 4
+         %15 = OpTypePointer Output %14
+          %3 = OpVariable %15 Output
+         %16 = OpTypeMatrix %14 4
+         %17 = OpTypeInt 32 0
+         %18 = OpConstant %17 72
+          %9 = OpTypeArray %14 %18
+         %10 = OpTypeArray %14 %18
+          %6 = OpTypeStruct %16 %9 %10
+         %19 = OpTypePointer Uniform %6
+          %7 = OpVariable %19 Uniform
+         %20 = OpTypeInt 32 1
+         %21 = OpConstant %20 2
+         %22 = OpTypePointer Input %20
+          %4 = OpVariable %22 Input
+         %23 = OpTypePointer Uniform %14
+          %8 = OpTypeStruct %14
+         %24 = OpTypePointer Output %8
+          %5 = OpVariable %24 Output
+         %25 = OpConstant %20 0
+         %26 = OpConstant %20 1
+         %27 = OpConstant %13 1
+         %28 = OpConstantComposite %14 %27 %27 %27 %27
+          %2 = OpFunction %11 None %12
+         %29 = OpLabel
+               OpBranch %30
+         %30 = OpLabel
+; CHECK: OpLoopMerge [[merge1:%[a-zA-Z_\d]+]]
+               OpLoopMerge %31 %32 None
+               OpBranch %33
+         %33 = OpLabel
+; CHECK: OpSelectionMerge [[sel_merge1:%[a-zA-Z_\d]+]]
+               OpSelectionMerge %34 None
+               OpSwitch %26 %35
+         %35 = OpLabel
+         %36 = OpLoad %20 %4
+         %37 = OpAccessChain %23 %7 %21 %36
+         %38 = OpLoad %14 %37
+               OpStore %3 %38
+         %39 = OpAccessChain %15 %5 %25
+               OpStore %39 %28
+               OpBranch %31
+; CHECK: [[sel_merge1]] = OpLabel
+         %34 = OpLabel
+; CHECK-NEXT: OpBranch [[merge1]]
+               OpUnreachable
+         %32 = OpLabel
+               OpBranch %30
+         %31 = OpLabel
+; CHECK: OpLoopMerge [[merge2:%[a-zA-Z_\d]+]]
+               OpLoopMerge %40 %41 None
+               OpBranch %42
+         %42 = OpLabel
+; CHECK: OpSelectionMerge [[sel_merge2:%[a-zA-Z_\d]+]]
+               OpSelectionMerge %43 None
+               OpSwitch %26 %44
+         %44 = OpLabel
+         %45 = OpLoad %20 %4
+         %46 = OpAccessChain %23 %7 %21 %45
+         %47 = OpLoad %14 %46
+               OpStore %3 %47
+         %48 = OpAccessChain %15 %5 %25
+               OpStore %48 %28
+               OpBranch %40
+; CHECK: [[sel_merge2]] = OpLabel
+         %43 = OpLabel
+; CHECK-NEXT: OpBranch [[merge2]]
+               OpUnreachable
+         %41 = OpLabel
+               OpBranch %31
+         %40 = OpLabel
+               OpReturn
+               OpFunctionEnd)";
+
+  SinglePassRunAndMatch<opt::Workaround1209>(text, false);
+}
+
+TEST_F(Workaround1209Test, LeaveUnreachableNotInLoop) {
+  const std::string text = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Vertex %main "main" %texcoord %gl_VertexIndex %_
+               OpSource GLSL 400
+               OpSourceExtension "GL_ARB_separate_shader_objects"
+               OpSourceExtension "GL_ARB_shading_language_420pack"
+               OpName %main "main"
+               OpName %texcoord "texcoord"
+               OpName %buf "buf"
+               OpMemberName %buf 0 "MVP"
+               OpMemberName %buf 1 "position"
+               OpMemberName %buf 2 "attr"
+               OpName %ubuf "ubuf"
+               OpName %gl_VertexIndex "gl_VertexIndex"
+               OpName %gl_PerVertex "gl_PerVertex"
+               OpMemberName %gl_PerVertex 0 "gl_Position"
+               OpName %_ ""
+               OpDecorate %texcoord Location 0
+               OpDecorate %_arr_v4float_uint_72 ArrayStride 16
+               OpDecorate %_arr_v4float_uint_72_0 ArrayStride 16
+               OpMemberDecorate %buf 0 ColMajor
+               OpMemberDecorate %buf 0 Offset 0
+               OpMemberDecorate %buf 0 MatrixStride 16
+               OpMemberDecorate %buf 1 Offset 64
+               OpMemberDecorate %buf 2 Offset 1216
+               OpDecorate %buf Block
+               OpDecorate %ubuf DescriptorSet 0
+               OpDecorate %ubuf Binding 0
+               OpDecorate %gl_VertexIndex BuiltIn VertexIndex
+               OpMemberDecorate %gl_PerVertex 0 BuiltIn Position
+               OpDecorate %gl_PerVertex Block
+       %void = OpTypeVoid
+         %12 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+   %texcoord = OpVariable %_ptr_Output_v4float Output
+%mat4v4float = OpTypeMatrix %v4float 4
+       %uint = OpTypeInt 32 0
+    %uint_72 = OpConstant %uint 72
+%_arr_v4float_uint_72 = OpTypeArray %v4float %uint_72
+%_arr_v4float_uint_72_0 = OpTypeArray %v4float %uint_72
+        %buf = OpTypeStruct %mat4v4float %_arr_v4float_uint_72 %_arr_v4float_uint_72_0
+%_ptr_Uniform_buf = OpTypePointer Uniform %buf
+       %ubuf = OpVariable %_ptr_Uniform_buf Uniform
+        %int = OpTypeInt 32 1
+      %int_2 = OpConstant %int 2
+%_ptr_Input_int = OpTypePointer Input %int
+%gl_VertexIndex = OpVariable %_ptr_Input_int Input
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+%gl_PerVertex = OpTypeStruct %v4float
+%_ptr_Output_gl_PerVertex = OpTypePointer Output %gl_PerVertex
+          %_ = OpVariable %_ptr_Output_gl_PerVertex Output
+      %int_0 = OpConstant %int 0
+      %int_1 = OpConstant %int 1
+    %float_1 = OpConstant %float 1
+         %28 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
+       %main = OpFunction %void None %12
+         %29 = OpLabel
+               OpBranch %30
+         %30 = OpLabel
+               OpSelectionMerge %34 None
+               OpSwitch %int_1 %35
+         %35 = OpLabel
+         %36 = OpLoad %int %gl_VertexIndex
+         %37 = OpAccessChain %_ptr_Uniform_v4float %ubuf %int_2 %36
+         %38 = OpLoad %v4float %37
+               OpStore %texcoord %38
+         %39 = OpAccessChain %_ptr_Output_v4float %_ %int_0
+               OpStore %39 %28
+               OpReturn
+         %34 = OpLabel
+; CHECK: OpUnreachable
+               OpUnreachable
+               OpFunctionEnd)";
+
+  SinglePassRunAndMatch<opt::Workaround1209>(text, false);
+}
+#endif
+}  // anonymous namespace
index 2f62b4c..dd5fea6 100644 (file)
@@ -253,6 +253,10 @@ Options (in lexicographical order):
                Replaces instructions with equivalent and less expensive ones.
   --strip-debug
                Remove all debug instructions.
+  --workaround-1209
+               Rewrites instructions for which there are known driver bugs to
+               avoid triggering those bugs.
+               Current workarounds: Avoid OpUnreachable in loops.
   --unify-const
                Remove the duplicated constants.
   -h, --help
@@ -441,6 +445,8 @@ OptStatus ParseFlags(int argc, const char** argv, Optimizer* optimizer,
         optimizer->RegisterPass(CreatePrivateToLocalPass());
       } else if (0 == strcmp(cur_arg, "--remove-duplicates")) {
         optimizer->RegisterPass(CreateRemoveDuplicatesPass());
+      } else if (0 == strcmp(cur_arg, "--workaround-1209")) {
+        optimizer->RegisterPass(CreateWorkaround1209Pass());
       } else if (0 == strcmp(cur_arg, "--relax-struct-store")) {
         options->relax_struct_store = true;
       } else if (0 == strcmp(cur_arg, "--skip-validation")) {