Remove DebugDeclare only for target variables in ssa-rewrite (#3511)

For each local variable, ssa-rewrite should remove its DebugDeclare
if and only if it is replaced by any number of DebugValues for store
and phi instructions.

For example, when we have two variables `a` whose DebugDeclare
will be replaced to DebugValues by ssa-rewrite pass and `b` whose
DebugDeclare will not be replaced, we have to remove only DebugDeclare
for `a`, not `b`.
diff --git a/source/opt/ir_context.cpp b/source/opt/ir_context.cpp
index 0791097..a56ff06 100644
--- a/source/opt/ir_context.cpp
+++ b/source/opt/ir_context.cpp
@@ -222,13 +222,6 @@
   return false;
 }
 
-void IRContext::KillDebugDeclareInsts(Function* fn) {
-  fn->ForEachInst([this](Instruction* inst) {
-    if (inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugDeclare)
-      KillInst(inst);
-  });
-}
-
 bool IRContext::ReplaceAllUsesWith(uint32_t before, uint32_t after) {
   return ReplaceAllUsesWithPredicate(
       before, after, [](Instruction*, uint32_t) { return true; });
diff --git a/source/opt/ir_context.h b/source/opt/ir_context.h
index 37be836..b193657 100644
--- a/source/opt/ir_context.h
+++ b/source/opt/ir_context.h
@@ -403,9 +403,6 @@
   // instruction exists.
   Instruction* KillInst(Instruction* inst);
 
-  // Deletes DebugDeclare instructions in the given function |fn|.
-  void KillDebugDeclareInsts(Function* fn);
-
   // Returns true if all of the given analyses are valid.
   bool AreAnalysesValid(Analysis set) { return (set & valid_analyses_) == set; }
 
diff --git a/source/opt/ssa_rewrite_pass.cpp b/source/opt/ssa_rewrite_pass.cpp
index e1fc4f2..d5bba5e 100644
--- a/source/opt/ssa_rewrite_pass.cpp
+++ b/source/opt/ssa_rewrite_pass.cpp
@@ -615,8 +615,6 @@
             << fp->PrettyPrint(0) << "\n";
 #endif
 
-  if (modified) pass_->context()->KillDebugDeclareInsts(fp);
-
   return modified ? Pass::Status::SuccessWithChange
                   : Pass::Status::SuccessWithoutChange;
 }
@@ -626,6 +624,12 @@
   for (auto& fn : *get_module()) {
     status =
         CombineStatus(status, SSARewriter(this).RewriteFunctionIntoSSA(&fn));
+    if (status == Status::SuccessWithChange) {
+      // Kill DebugDeclares for target variables.
+      for (auto var_id : seen_target_vars_) {
+        context()->get_debug_info_mgr()->KillDebugDeclares(var_id);
+      }
+    }
     if (status == Status::Failure) {
       break;
     }
diff --git a/test/opt/local_ssa_elim_test.cpp b/test/opt/local_ssa_elim_test.cpp
index 6581ebf..8727e35 100644
--- a/test/opt/local_ssa_elim_test.cpp
+++ b/test/opt/local_ssa_elim_test.cpp
@@ -2165,6 +2165,135 @@
   SinglePassRunAndMatch<SSARewritePass>(text, true);
 }
 
+TEST_F(LocalSSAElimTest, PartiallyKillDebugDeclare) {
+  // For a reference variable e.g., int i in the following example,
+  // we do not propagate DebugValue for a store or phi instruction
+  // out of the variable's scope. In that case, we should not remove
+  // DebugDeclare for the variable that we did not add its DebugValue.
+  //
+  // #version 140
+  //
+  // in vec4 BC;
+  // out float fo;
+  //
+  // int j;
+  // void main()
+  // {
+  //     float f = 0.0;
+  //     for (j=0; j<4; j++) {
+  //       int& i = j;
+  //       f = f + BC[i];
+  //     }
+  //     fo = f;
+  // }
+
+  const std::string text = R"(
+; CHECK: [[f_name:%\w+]] = OpString "f"
+; CHECK: [[i_name:%\w+]] = OpString "i"
+; CHECK: [[fn:%\w+]] = OpExtInst %void [[ext:%\d+]] DebugFunction
+; CHECK: [[bb:%\w+]] = OpExtInst %void [[ext]] DebugLexicalBlock
+; CHECK: [[dbg_f:%\w+]] = OpExtInst %void [[ext]] DebugLocalVariable [[f_name]] {{%\w+}} {{%\w+}} 0 0 [[fn]]
+; CHECK: [[dbg_i:%\w+]] = OpExtInst %void [[ext]] DebugLocalVariable [[i_name]] {{%\w+}} {{%\w+}} 0 0 [[bb]]
+
+; CHECK:      OpStore %f %float_0
+; CHECK-NEXT: OpExtInst %void [[ext]] DebugValue [[dbg_f]] %float_0
+; CHECK-NOT:  DebugDeclare [[dbg_f]]
+; CHECK:      OpExtInst %void [[ext]] DebugDeclare [[dbg_i]] %j
+
+OpCapability Shader
+%1 = OpExtInstImport "GLSL.std.450"
+%ext = OpExtInstImport "OpenCL.DebugInfo.100"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main" %BC %fo
+OpExecutionMode %main OriginUpperLeft
+%file_name = OpString "test"
+OpSource GLSL 140
+%float_name = OpString "float"
+%main_name = OpString "main"
+%f_name = OpString "f"
+%i_name = OpString "i"
+%j_name = OpString "j"
+OpName %main "main"
+OpName %f "f"
+OpName %j "j"
+OpName %BC "BC"
+OpName %fo "fo"
+%void = OpTypeVoid
+%8 = OpTypeFunction %void
+%float = OpTypeFloat 32
+%_ptr_Function_float = OpTypePointer Function %float
+%float_0 = OpConstant %float 0
+%int = OpTypeInt 32 1
+%uint = OpTypeInt 32 0
+%uint_32 = OpConstant %uint 32
+%_ptr_Function_int = OpTypePointer Function %int
+%_ptr_Private_int = OpTypePointer Private %int
+%int_0 = OpConstant %int 0
+%int_4 = OpConstant %int 4
+%bool = OpTypeBool
+%v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+%BC = OpVariable %_ptr_Input_v4float Input
+%_ptr_Input_float = OpTypePointer Input %float
+%int_1 = OpConstant %int 1
+%_ptr_Output_float = OpTypePointer Output %float
+%fo = OpVariable %_ptr_Output_float Output
+%j = OpVariable %_ptr_Private_int Private
+%null_expr = OpExtInst %void %ext DebugExpression
+%src = OpExtInst %void %ext DebugSource %file_name
+%cu = OpExtInst %void %ext DebugCompilationUnit 1 4 %src HLSL
+%dbg_tf = OpExtInst %void %ext DebugTypeBasic %float_name %uint_32 Float
+%dbg_v4f = OpExtInst %void %ext DebugTypeVector %dbg_tf 4
+%main_ty = OpExtInst %void %ext DebugTypeFunction FlagIsProtected|FlagIsPrivate %dbg_v4f %dbg_v4f
+%dbg_main = OpExtInst %void %ext DebugFunction %main_name %main_ty %src 0 0 %cu %main_name FlagIsProtected|FlagIsPrivate 10 %main
+%bb = OpExtInst %void %ext DebugLexicalBlock %src 0 0 %dbg_main
+%dbg_f = OpExtInst %void %ext DebugLocalVariable %f_name %dbg_v4f %src 0 0 %dbg_main FlagIsLocal
+%dbg_i = OpExtInst %void %ext DebugLocalVariable %i_name %dbg_v4f %src 0 0 %bb FlagIsLocal
+%dbg_j = OpExtInst %void %ext DebugGlobalVariable %j_name %dbg_v4f %src 0 0 %dbg_main %j_name %j FlagIsPrivate
+%main = OpFunction %void None %8
+%22 = OpLabel
+%s0 = OpExtInst %void %ext DebugScope %dbg_main
+%f = OpVariable %_ptr_Function_float Function
+OpStore %f %float_0
+OpStore %j %int_0
+%decl0 = OpExtInst %void %ext DebugDeclare %dbg_f %f %null_expr
+OpBranch %23
+%23 = OpLabel
+%s1 = OpExtInst %void %ext DebugScope %dbg_main
+OpLoopMerge %24 %25 None
+OpBranch %26
+%26 = OpLabel
+%s2 = OpExtInst %void %ext DebugScope %dbg_main
+%27 = OpLoad %int %j
+%28 = OpSLessThan %bool %27 %int_4
+OpBranchConditional %28 %29 %24
+%29 = OpLabel
+%s3 = OpExtInst %void %ext DebugScope %bb
+%decl1 = OpExtInst %void %ext DebugDeclare %dbg_i %j %null_expr
+%30 = OpLoad %float %f
+%31 = OpLoad %int %j
+%32 = OpAccessChain %_ptr_Input_float %BC %31
+%33 = OpLoad %float %32
+%34 = OpFAdd %float %30 %33
+OpStore %f %34
+OpBranch %25
+%25 = OpLabel
+%s4 = OpExtInst %void %ext DebugScope %dbg_main
+%35 = OpLoad %int %j
+%36 = OpIAdd %int %35 %int_1
+OpStore %j %36
+OpBranch %23
+%24 = OpLabel
+%s5 = OpExtInst %void %ext DebugScope %dbg_main
+%37 = OpLoad %float %f
+OpStore %fo %37
+OpReturn
+OpFunctionEnd
+)";
+
+  SinglePassRunAndMatch<SSARewritePass>(text, true);
+}
+
 TEST_F(LocalSSAElimTest, DebugValueForReferenceVariable) {
   // #version 140
   //