From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Antonio Maiorano <amaiorano@google.com>
Date: Fri, 24 May 2024 15:51:26 -0400
Subject: Fix dxil-remove-dead-blocks removing switch with multiple same
 successor (#6610)

Given a switch with a constant condition and all cases the same
(branching to the same successor), dxil-remove-dead-blocks would
incorrectly remove the switch when replacing it with a branch, by
forgetting to remove the N-1 incoming values to the PHIs in the
successor block.

Bug: chromium:338071106
Change-Id: Iaa2c42642f3e370afd19d88c96c81056c16349b6
Reviewed-on: https://chromium-review.googlesource.com/c/external/github.com/microsoft/DirectXShaderCompiler/+/5570270
Reviewed-by: Ben Clayton <bclayton@chromium.org>
Reviewed-by: James Price <jrprice@google.com>

diff --git a/lib/Transforms/Scalar/DxilRemoveDeadBlocks.cpp b/lib/Transforms/Scalar/DxilRemoveDeadBlocks.cpp
index 54308eed2e018903e518be4a5ff809e080be78c0..9a87f4e6740c8da0522c6bf00f2a365f838cb3c0 100644
--- a/lib/Transforms/Scalar/DxilRemoveDeadBlocks.cpp
+++ b/lib/Transforms/Scalar/DxilRemoveDeadBlocks.cpp
@@ -35,6 +35,7 @@
 using namespace llvm;
 using namespace hlsl;
 
+// Removes BB from PHI nodes in SuccBB, deleting the PHI nodes if empty.
 static void RemoveIncomingValueFrom(BasicBlock *SuccBB, BasicBlock *BB) {
   for (auto inst_it = SuccBB->begin(); inst_it != SuccBB->end();) {
     Instruction *I = &*(inst_it++);
@@ -105,6 +106,8 @@ bool DeadBlockDeleter::Run(Function &F, DxilValueCache *DVC) {
     } else if (SwitchInst *Switch = dyn_cast<SwitchInst>(BB->getTerminator())) {
       Value *Cond = Switch->getCondition();
       BasicBlock *Succ = nullptr;
+      // If the condition to Switch is constant, replace Switch with a branch
+      // to the current case successor.
       if (ConstantInt *ConstCond = DVC->GetConstInt(Cond)) {
         Succ = hlsl::dxilutil::GetSwitchSuccessorForCond(Switch, ConstCond);
       }
@@ -112,16 +115,32 @@ bool DeadBlockDeleter::Run(Function &F, DxilValueCache *DVC) {
       if (Succ) {
         Add(Succ);
 
+        // Create branch from BB to Succ that will replace Switch.
+        // This adds BB to preds of Succ.
         BranchInst *NewBr = BranchInst::Create(Succ, BB);
         hlsl::DxilMDHelper::CopyMetadata(*NewBr, *Switch);
 
+        // For any successors we're not going to, remove incoming block BB from
+        // PHI nodes in those successors.
+        unsigned numSucc = 0;
         for (unsigned i = 0; i < Switch->getNumSuccessors(); i++) {
           BasicBlock *NotSucc = Switch->getSuccessor(i);
-          if (NotSucc != Succ) {
+          if (NotSucc != Succ)
             RemoveIncomingValueFrom(NotSucc, BB);
-          }
+          else
+            ++numSucc;
+        }
+
+        // We're replacing Switch with a single unconditional branch. If Switch
+        // has N cases with the same Succ, we need to remove N-1 incoming values
+        // of BB from the PHI nodes in Succ. This ensures that the preds of Succ
+        // match the ones in its PHIs.
+        for (unsigned i = 1; i < numSucc; i++) {
+          RemoveIncomingValueFrom(Succ, BB);
         }
 
+        // Finally, erase Switch, which will remove BB as pred from all
+        // successors.
         Switch->eraseFromParent();
         Switch = nullptr;
         Changed = true;
diff --git a/tools/clang/test/DXC/Passes/DxilRemoveDeadBlocks/switch-with-multiple-same-successor.hlsl b/tools/clang/test/DXC/Passes/DxilRemoveDeadBlocks/switch-with-multiple-same-successor.hlsl
new file mode 100644
index 0000000000000000000000000000000000000000..43c3510b2ce18b15ff74a0db4697898da807f49f
--- /dev/null
+++ b/tools/clang/test/DXC/Passes/DxilRemoveDeadBlocks/switch-with-multiple-same-successor.hlsl
@@ -0,0 +1,68 @@
+// Test switch with multiple same successors
+// RUN: %dxc -T ps_6_6 %s | FileCheck %s
+
+// This test used to fail with validation errors:
+//
+// error: validation errors
+// error: Module bitcode is invalid.
+// error: PHINode should have one entry for each predecessor of its parent basic block!
+//   %22 = phi i32 [ 1, %20 ], [ 1, %20 ], [ 1, %20 ], [ 1, %20 ], [ %11, %13 ]
+// PHINode should have one entry for each predecessor of its parent basic block!
+//   %28 = phi i32 [ 1, %26 ], [ 1, %26 ], [ 1, %26 ], [ 1, %26 ], [ %22, %24 ]
+// PHINode should have one entry for each predecessor of its parent basic block!
+//   %34 = phi i32 [ 1, %32 ], [ 1, %32 ], [ 1, %32 ], [ 1, %32 ], [ %28, %30 ]
+// PHINode should have one entry for each predecessor of its parent basic block!
+//   %47 = phi i32 [ 1, %45 ], [ 1, %45 ], [ 1, %45 ], [ 1, %45 ], [ %41, %43 ]
+//
+// This was fixed in dxil-remove-dead-blocks. See switch-with-multiple-same-successor.ll
+// for the pass-specific checks. Here, we just want to make sure dxc compiles this without error.
+
+// CHECK: @main
+
+ByteAddressBuffer g_buff : register(t0);
+
+struct retval {
+  float4 value : SV_Target0;
+};
+
+retval main() {
+  float4 g = asfloat(g_buff.Load4(0u));
+  bool do_discard = false;
+
+  for (int i = 0; i < 10; ++i) {
+    if (g.x != 0.0f)
+      continue;
+
+    // Switch with the same successor in all cases
+    switch(i) {
+      case 1: {
+        g.x = g.x;
+        break;
+      }
+      case 2: {
+        g.x = g.x;
+        break;
+      }
+      case 3: {
+        g.x = g.x;
+        break;
+      }
+      // Skip 'case 4' to avoid case range combining
+      case 5: {
+        g.x = g.x;
+        break;
+      }
+    }
+    if (i == 6) {
+      break;
+    }
+    g.x = atan2(1.0f, g.x);
+    do_discard = true;
+  }
+
+  if (do_discard) {
+    discard;
+  }
+
+  return (retval)0;
+}
diff --git a/tools/clang/test/DXC/Passes/DxilRemoveDeadBlocks/switch-with-multiple-same-successor.ll b/tools/clang/test/DXC/Passes/DxilRemoveDeadBlocks/switch-with-multiple-same-successor.ll
new file mode 100644
index 0000000000000000000000000000000000000000..d3e7e2f1e40c816c4ed28bfc45a1569e130f472c
--- /dev/null
+++ b/tools/clang/test/DXC/Passes/DxilRemoveDeadBlocks/switch-with-multiple-same-successor.ll
@@ -0,0 +1,369 @@
+; RUN: %dxopt %s -hlsl-passes-resume -dxil-remove-dead-blocks -S | FileCheck %s
+
+; Validate that a switch with a constant condition and multiple of the same successor
+; is correctly removed, ensuring that PHIs in the successor are properly updated.
+; For instance, in:
+;
+;
+; if.end.1:                                         ; preds = %for.inc
+;   switch i32 1, label %sw.epilog.1 [
+;     i32 1, label %dx.struct_exit.new_exiting.1
+;     i32 2, label %dx.struct_exit.new_exiting.1
+;     i32 3, label %dx.struct_exit.new_exiting.1
+;     i32 5, label %dx.struct_exit.new_exiting.1
+;   ], !dbg !31 ; line:23 col:5
+;
+; sw.epilog.1:                                      ; preds = %if.end.1
+;   br label %dx.struct_exit.new_exiting.1
+;
+; dx.struct_exit.new_exiting.1:                     ; preds = %sw.epilog.1, %if.end.1, %if.end.1, %if.end.1, %if.end.1, %for.inc
+;   %dx.struct_exit.prop.1 = phi i32 [ %do_discard.2, %sw.epilog.1 ], [ 0, %if.end.1 ], [ 0, %if.end.1 ], [ 0, %if.end.1 ], [ 0, %if.end.1 ], [ 0, %for.inc ]
+;   %do_discard.2.1 = phi i32 [ 1, %sw.epilog.1 ], [ 1, %if.end.1 ], [ 1, %if.end.1 ], [ 1, %if.end.1 ], [ 1, %if.end.1 ], [ %do_discard.2, %for.inc ]
+;   %g.2.i0.1 = phi float [ 0x3FF921FB60000000, %sw.epilog.1 ], [ 0x3FF921FB60000000, %if.end.1 ], [ 0x3FF921FB60000000, %if.end.1 ], [ 0x3FF921FB60000000, %if.end.1 ], [ 0x3FF921FB60000000, %if.end.1 ], [ %g.2.i0, %for.inc ]
+;   br i1 false, label %cleanup, label %for.inc.1
+;
+;
+; After dxil-remove-dead-blocks, the multiple `%if.end.1` in preds and in the two phi instructions should be removed,
+; and only one instance should be left.
+
+; CHECK:      if.end.1:                                         ; preds = %for.inc
+; CHECK-NEXT:   br label %dx.struct_exit.new_exiting.1
+
+; CHECK:     dx.struct_exit.new_exiting.1:                     ; preds = %if.end.1, %for.inc
+; CHECK-NEXT:  %do_discard.2.1 = phi i32 [ 1, %if.end.1 ], [ %do_discard.2, %for.inc ]
+; CHECK-NEXT:  %g.2.i0.1 = phi float [ 0x3FF921FB60000000, %if.end.1 ], [ %g.2.i0, %for.inc ]
+
+;
+; Output signature:
+;
+; Name                 Index             InterpMode DynIdx
+; -------------------- ----- ---------------------- ------
+; SV_Target                0
+;
+; Buffer Definitions:
+;
+;
+; Resource Bindings:
+;
+; Name                                 Type  Format         Dim      ID      HLSL Bind  Count
+; ------------------------------ ---------- ------- ----------- ------- -------------- ------
+; g_buff                            texture    byte         r/o      T0             t0     1
+;
+target datalayout = "e-m:e-p:32:32-i1:32-i8:32-i16:32-i32:32-i64:64-f16:32-f32:32-f64:64-n8:16:32:64"
+target triple = "dxil-ms-dx"
+
+%struct.ByteAddressBuffer = type { i32 }
+%dx.types.Handle = type { i8* }
+%dx.types.ResourceProperties = type { i32, i32 }
+%dx.types.ResRet.i32 = type { i32, i32, i32, i32, i32 }
+%struct.retval = type { <4 x float> }
+
+@"\01?g_buff@@3UByteAddressBuffer@@A" = external global %struct.ByteAddressBuffer, align 4
+@llvm.used = appending global [1 x i8*] [i8* bitcast (%struct.ByteAddressBuffer* @"\01?g_buff@@3UByteAddressBuffer@@A" to i8*)], section "llvm.metadata"
+
+; Function Attrs: nounwind
+define void @main(<4 x float>* noalias nocapture readnone) #0 {
+for.body.lr.ph:
+  %1 = load %struct.ByteAddressBuffer, %struct.ByteAddressBuffer* @"\01?g_buff@@3UByteAddressBuffer@@A", align 4, !dbg !23 ; line:15 col:22
+  %2 = call %dx.types.Handle @dx.op.createHandleForLib.struct.ByteAddressBuffer(i32 160, %struct.ByteAddressBuffer %1), !dbg !23 ; line:15 col:22  ; CreateHandleForLib(Resource)
+  %3 = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle %2, %dx.types.ResourceProperties { i32 11, i32 0 }), !dbg !23 ; line:15 col:22  ; AnnotateHandle(res,props)  resource: ByteAddressBuffer
+  %RawBufferLoad = call %dx.types.ResRet.i32 @dx.op.rawBufferLoad.i32(i32 139, %dx.types.Handle %3, i32 0, i32 undef, i8 15, i32 4), !dbg !23 ; line:15 col:22  ; RawBufferLoad(srv,index,elementOffset,mask,alignment)
+  %4 = extractvalue %dx.types.ResRet.i32 %RawBufferLoad, 0, !dbg !23 ; line:15 col:22
+  %.i0 = bitcast i32 %4 to float, !dbg !27 ; line:15 col:14
+  br label %for.body, !dbg !28 ; line:18 col:3
+
+for.body:                                         ; preds = %for.body.lr.ph
+  %cmp3 = fcmp fast une float %.i0, 0.000000e+00, !dbg !29 ; line:19 col:13
+  br i1 %cmp3, label %dx.struct_exit.new_exiting, label %if.end, !dbg !30 ; line:19 col:9
+
+if.end:                                           ; preds = %for.body
+  switch i32 0, label %sw.epilog [
+    i32 1, label %dx.struct_exit.new_exiting
+    i32 2, label %dx.struct_exit.new_exiting
+    i32 3, label %dx.struct_exit.new_exiting
+    i32 5, label %dx.struct_exit.new_exiting
+  ], !dbg !31 ; line:23 col:5
+
+sw.epilog:                                        ; preds = %if.end
+  br label %dx.struct_exit.new_exiting
+
+dx.struct_exit.new_exiting:                       ; preds = %sw.epilog, %if.end, %if.end, %if.end, %if.end, %for.body
+  %do_discard.2 = phi i32 [ 0, %for.body ], [ 1, %if.end ], [ 1, %if.end ], [ 1, %if.end ], [ 1, %if.end ], [ 1, %sw.epilog ]
+  %g.2.i0 = phi float [ %.i0, %for.body ], [ 0x3FF921FB60000000, %if.end ], [ 0x3FF921FB60000000, %if.end ], [ 0x3FF921FB60000000, %if.end ], [ 0x3FF921FB60000000, %if.end ], [ 0x3FF921FB60000000, %sw.epilog ]
+  br i1 false, label %cleanup, label %for.inc
+
+for.inc:                                          ; preds = %dx.struct_exit.new_exiting
+  %cmp3.1 = fcmp fast une float %g.2.i0, 0.000000e+00, !dbg !29 ; line:19 col:13
+  br i1 %cmp3.1, label %dx.struct_exit.new_exiting.1, label %if.end.1, !dbg !30 ; line:19 col:9
+
+cleanup:                                          ; preds = %for.inc.9, %dx.struct_exit.new_exiting.9, %dx.struct_exit.new_exiting.8, %dx.struct_exit.new_exiting.7, %dx.struct_exit.new_exiting.6, %dx.struct_exit.new_exiting.5, %dx.struct_exit.new_exiting.4, %dx.struct_exit.new_exiting.3, %dx.struct_exit.new_exiting.2, %dx.struct_exit.new_exiting.1, %dx.struct_exit.new_exiting
+  %do_discard.3 = phi i32 [ 0, %dx.struct_exit.new_exiting ], [ %dx.struct_exit.prop.1, %dx.struct_exit.new_exiting.1 ], [ %dx.struct_exit.prop.2, %dx.struct_exit.new_exiting.2 ], [ %dx.struct_exit.prop.3, %dx.struct_exit.new_exiting.3 ], [ %dx.struct_exit.prop.4, %dx.struct_exit.new_exiting.4 ], [ %dx.struct_exit.prop.5, %dx.struct_exit.new_exiting.5 ], [ %dx.struct_exit.prop.6, %dx.struct_exit.new_exiting.6 ], [ %dx.struct_exit.prop.7, %dx.struct_exit.new_exiting.7 ], [ %dx.struct_exit.prop.8, %dx.struct_exit.new_exiting.8 ], [ %dx.struct_exit.prop.9, %dx.struct_exit.new_exiting.9 ], [ %do_discard.2.9, %for.inc.9 ]
+  %tobool15 = icmp eq i32 %do_discard.3, 0, !dbg !32 ; line:49 col:7
+  br i1 %tobool15, label %if.end.17, label %if.then.16, !dbg !32 ; line:49 col:7
+
+if.then.16:                                       ; preds = %cleanup
+  call void @dx.op.discard(i32 82, i1 true), !dbg !33 ; line:49 col:19  ; Discard(condition)
+  br label %if.end.17, !dbg !34 ; line:51 col:3
+
+if.end.17:                                        ; preds = %cleanup, %if.then.16
+  call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 0, float 0.000000e+00), !dbg !35 ; line:53 col:18  ; StoreOutput(outputSigId,rowIndex,colIndex,value)
+  call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 1, float 0.000000e+00), !dbg !35 ; line:53 col:18  ; StoreOutput(outputSigId,rowIndex,colIndex,value)
+  call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 2, float 0.000000e+00), !dbg !35 ; line:53 col:18  ; StoreOutput(outputSigId,rowIndex,colIndex,value)
+  call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 3, float 0.000000e+00), !dbg !35 ; line:53 col:18  ; StoreOutput(outputSigId,rowIndex,colIndex,value)
+  ret void, !dbg !36 ; line:54 col:1
+
+if.end.1:                                         ; preds = %for.inc
+  switch i32 1, label %sw.epilog.1 [
+    i32 1, label %dx.struct_exit.new_exiting.1
+    i32 2, label %dx.struct_exit.new_exiting.1
+    i32 3, label %dx.struct_exit.new_exiting.1
+    i32 5, label %dx.struct_exit.new_exiting.1
+  ], !dbg !31 ; line:23 col:5
+
+sw.epilog.1:                                      ; preds = %if.end.1
+  br label %dx.struct_exit.new_exiting.1
+
+dx.struct_exit.new_exiting.1:                     ; preds = %sw.epilog.1, %if.end.1, %if.end.1, %if.end.1, %if.end.1, %for.inc
+  %dx.struct_exit.prop.1 = phi i32 [ %do_discard.2, %sw.epilog.1 ], [ 0, %if.end.1 ], [ 0, %if.end.1 ], [ 0, %if.end.1 ], [ 0, %if.end.1 ], [ 0, %for.inc ]
+  %do_discard.2.1 = phi i32 [ 1, %sw.epilog.1 ], [ 1, %if.end.1 ], [ 1, %if.end.1 ], [ 1, %if.end.1 ], [ 1, %if.end.1 ], [ %do_discard.2, %for.inc ]
+  %g.2.i0.1 = phi float [ 0x3FF921FB60000000, %sw.epilog.1 ], [ 0x3FF921FB60000000, %if.end.1 ], [ 0x3FF921FB60000000, %if.end.1 ], [ 0x3FF921FB60000000, %if.end.1 ], [ 0x3FF921FB60000000, %if.end.1 ], [ %g.2.i0, %for.inc ]
+  br i1 false, label %cleanup, label %for.inc.1
+
+for.inc.1:                                        ; preds = %dx.struct_exit.new_exiting.1
+  %cmp3.2 = fcmp fast une float %g.2.i0.1, 0.000000e+00, !dbg !29 ; line:19 col:13
+  br i1 %cmp3.2, label %dx.struct_exit.new_exiting.2, label %if.end.2, !dbg !30 ; line:19 col:9
+
+if.end.2:                                         ; preds = %for.inc.1
+  switch i32 2, label %sw.epilog.2 [
+    i32 1, label %dx.struct_exit.new_exiting.2
+    i32 2, label %dx.struct_exit.new_exiting.2
+    i32 3, label %dx.struct_exit.new_exiting.2
+    i32 5, label %dx.struct_exit.new_exiting.2
+  ], !dbg !31 ; line:23 col:5
+
+sw.epilog.2:                                      ; preds = %if.end.2
+  br label %dx.struct_exit.new_exiting.2
+
+dx.struct_exit.new_exiting.2:                     ; preds = %sw.epilog.2, %if.end.2, %if.end.2, %if.end.2, %if.end.2, %for.inc.1
+  %dx.struct_exit.prop.2 = phi i32 [ %do_discard.2.1, %sw.epilog.2 ], [ 0, %if.end.2 ], [ 0, %if.end.2 ], [ 0, %if.end.2 ], [ 0, %if.end.2 ], [ 0, %for.inc.1 ]
+  %do_discard.2.2 = phi i32 [ 1, %sw.epilog.2 ], [ 1, %if.end.2 ], [ 1, %if.end.2 ], [ 1, %if.end.2 ], [ 1, %if.end.2 ], [ %do_discard.2.1, %for.inc.1 ]
+  %g.2.i0.2 = phi float [ 0x3FF921FB60000000, %sw.epilog.2 ], [ 0x3FF921FB60000000, %if.end.2 ], [ 0x3FF921FB60000000, %if.end.2 ], [ 0x3FF921FB60000000, %if.end.2 ], [ 0x3FF921FB60000000, %if.end.2 ], [ %g.2.i0.1, %for.inc.1 ]
+  br i1 false, label %cleanup, label %for.inc.2
+
+for.inc.2:                                        ; preds = %dx.struct_exit.new_exiting.2
+  %cmp3.3 = fcmp fast une float %g.2.i0.2, 0.000000e+00, !dbg !29 ; line:19 col:13
+  br i1 %cmp3.3, label %dx.struct_exit.new_exiting.3, label %if.end.3, !dbg !30 ; line:19 col:9
+
+if.end.3:                                         ; preds = %for.inc.2
+  switch i32 3, label %sw.epilog.3 [
+    i32 1, label %dx.struct_exit.new_exiting.3
+    i32 2, label %dx.struct_exit.new_exiting.3
+    i32 3, label %dx.struct_exit.new_exiting.3
+    i32 5, label %dx.struct_exit.new_exiting.3
+  ], !dbg !31 ; line:23 col:5
+
+sw.epilog.3:                                      ; preds = %if.end.3
+  br label %dx.struct_exit.new_exiting.3
+
+dx.struct_exit.new_exiting.3:                     ; preds = %sw.epilog.3, %if.end.3, %if.end.3, %if.end.3, %if.end.3, %for.inc.2
+  %dx.struct_exit.prop.3 = phi i32 [ %do_discard.2.2, %sw.epilog.3 ], [ 0, %if.end.3 ], [ 0, %if.end.3 ], [ 0, %if.end.3 ], [ 0, %if.end.3 ], [ 0, %for.inc.2 ]
+  %do_discard.2.3 = phi i32 [ 1, %sw.epilog.3 ], [ 1, %if.end.3 ], [ 1, %if.end.3 ], [ 1, %if.end.3 ], [ 1, %if.end.3 ], [ %do_discard.2.2, %for.inc.2 ]
+  %g.2.i0.3 = phi float [ 0x3FF921FB60000000, %sw.epilog.3 ], [ 0x3FF921FB60000000, %if.end.3 ], [ 0x3FF921FB60000000, %if.end.3 ], [ 0x3FF921FB60000000, %if.end.3 ], [ 0x3FF921FB60000000, %if.end.3 ], [ %g.2.i0.2, %for.inc.2 ]
+  br i1 false, label %cleanup, label %for.inc.3
+
+for.inc.3:                                        ; preds = %dx.struct_exit.new_exiting.3
+  %cmp3.4 = fcmp fast une float %g.2.i0.3, 0.000000e+00, !dbg !29 ; line:19 col:13
+  br i1 %cmp3.4, label %dx.struct_exit.new_exiting.4, label %if.end.4, !dbg !30 ; line:19 col:9
+
+if.end.4:                                         ; preds = %for.inc.3
+  switch i32 4, label %sw.epilog.4 [
+    i32 1, label %dx.struct_exit.new_exiting.4
+    i32 2, label %dx.struct_exit.new_exiting.4
+    i32 3, label %dx.struct_exit.new_exiting.4
+    i32 5, label %dx.struct_exit.new_exiting.4
+  ], !dbg !31 ; line:23 col:5
+
+sw.epilog.4:                                      ; preds = %if.end.4
+  br label %dx.struct_exit.new_exiting.4
+
+dx.struct_exit.new_exiting.4:                     ; preds = %sw.epilog.4, %if.end.4, %if.end.4, %if.end.4, %if.end.4, %for.inc.3
+  %dx.struct_exit.prop.4 = phi i32 [ %do_discard.2.3, %sw.epilog.4 ], [ 0, %if.end.4 ], [ 0, %if.end.4 ], [ 0, %if.end.4 ], [ 0, %if.end.4 ], [ 0, %for.inc.3 ]
+  %do_discard.2.4 = phi i32 [ 1, %sw.epilog.4 ], [ 1, %if.end.4 ], [ 1, %if.end.4 ], [ 1, %if.end.4 ], [ 1, %if.end.4 ], [ %do_discard.2.3, %for.inc.3 ]
+  %g.2.i0.4 = phi float [ 0x3FF921FB60000000, %sw.epilog.4 ], [ 0x3FF921FB60000000, %if.end.4 ], [ 0x3FF921FB60000000, %if.end.4 ], [ 0x3FF921FB60000000, %if.end.4 ], [ 0x3FF921FB60000000, %if.end.4 ], [ %g.2.i0.3, %for.inc.3 ]
+  br i1 false, label %cleanup, label %for.inc.4
+
+for.inc.4:                                        ; preds = %dx.struct_exit.new_exiting.4
+  %cmp3.5 = fcmp fast une float %g.2.i0.4, 0.000000e+00, !dbg !29 ; line:19 col:13
+  br i1 %cmp3.5, label %dx.struct_exit.new_exiting.5, label %if.end.5, !dbg !30 ; line:19 col:9
+
+if.end.5:                                         ; preds = %for.inc.4
+  switch i32 5, label %sw.epilog.5 [
+    i32 1, label %dx.struct_exit.new_exiting.5
+    i32 2, label %dx.struct_exit.new_exiting.5
+    i32 3, label %dx.struct_exit.new_exiting.5
+    i32 5, label %dx.struct_exit.new_exiting.5
+  ], !dbg !31 ; line:23 col:5
+
+sw.epilog.5:                                      ; preds = %if.end.5
+  br label %dx.struct_exit.new_exiting.5
+
+dx.struct_exit.new_exiting.5:                     ; preds = %sw.epilog.5, %if.end.5, %if.end.5, %if.end.5, %if.end.5, %for.inc.4
+  %dx.struct_exit.prop.5 = phi i32 [ %do_discard.2.4, %sw.epilog.5 ], [ 0, %if.end.5 ], [ 0, %if.end.5 ], [ 0, %if.end.5 ], [ 0, %if.end.5 ], [ 0, %for.inc.4 ]
+  %do_discard.2.5 = phi i32 [ 1, %sw.epilog.5 ], [ 1, %if.end.5 ], [ 1, %if.end.5 ], [ 1, %if.end.5 ], [ 1, %if.end.5 ], [ %do_discard.2.4, %for.inc.4 ]
+  %g.2.i0.5 = phi float [ 0x3FF921FB60000000, %sw.epilog.5 ], [ 0x3FF921FB60000000, %if.end.5 ], [ 0x3FF921FB60000000, %if.end.5 ], [ 0x3FF921FB60000000, %if.end.5 ], [ 0x3FF921FB60000000, %if.end.5 ], [ %g.2.i0.4, %for.inc.4 ]
+  br i1 false, label %cleanup, label %for.inc.5
+
+for.inc.5:                                        ; preds = %dx.struct_exit.new_exiting.5
+  %cmp3.6 = fcmp fast une float %g.2.i0.5, 0.000000e+00, !dbg !29 ; line:19 col:13
+  br i1 %cmp3.6, label %dx.struct_exit.new_exiting.6, label %if.end.6, !dbg !30 ; line:19 col:9
+
+if.end.6:                                         ; preds = %for.inc.5
+  switch i32 6, label %sw.epilog.6 [
+    i32 1, label %dx.struct_exit.new_exiting.6
+    i32 2, label %dx.struct_exit.new_exiting.6
+    i32 3, label %dx.struct_exit.new_exiting.6
+    i32 5, label %dx.struct_exit.new_exiting.6
+  ], !dbg !31 ; line:23 col:5
+
+sw.epilog.6:                                      ; preds = %if.end.6
+  br label %dx.struct_exit.new_exiting.6
+
+dx.struct_exit.new_exiting.6:                     ; preds = %sw.epilog.6, %if.end.6, %if.end.6, %if.end.6, %if.end.6, %for.inc.5
+  %dx.struct_exit.prop23.6 = phi i1 [ true, %sw.epilog.6 ], [ false, %if.end.6 ], [ false, %if.end.6 ], [ false, %if.end.6 ], [ false, %if.end.6 ], [ false, %for.inc.5 ]
+  %dx.struct_exit.prop.6 = phi i32 [ %do_discard.2.5, %sw.epilog.6 ], [ 0, %if.end.6 ], [ 0, %if.end.6 ], [ 0, %if.end.6 ], [ 0, %if.end.6 ], [ 0, %for.inc.5 ]
+  %do_discard.2.6 = phi i32 [ 1, %sw.epilog.6 ], [ 1, %if.end.6 ], [ 1, %if.end.6 ], [ 1, %if.end.6 ], [ 1, %if.end.6 ], [ %do_discard.2.5, %for.inc.5 ]
+  %g.2.i0.6 = phi float [ 0x3FF921FB60000000, %sw.epilog.6 ], [ 0x3FF921FB60000000, %if.end.6 ], [ 0x3FF921FB60000000, %if.end.6 ], [ 0x3FF921FB60000000, %if.end.6 ], [ 0x3FF921FB60000000, %if.end.6 ], [ %g.2.i0.5, %for.inc.5 ]
+  br i1 %dx.struct_exit.prop23.6, label %cleanup, label %for.inc.6
+
+for.inc.6:                                        ; preds = %dx.struct_exit.new_exiting.6
+  %cmp3.7 = fcmp fast une float %g.2.i0.6, 0.000000e+00, !dbg !29 ; line:19 col:13
+  br i1 %cmp3.7, label %dx.struct_exit.new_exiting.7, label %if.end.7, !dbg !30 ; line:19 col:9
+
+if.end.7:                                         ; preds = %for.inc.6
+  switch i32 7, label %sw.epilog.7 [
+    i32 1, label %dx.struct_exit.new_exiting.7
+    i32 2, label %dx.struct_exit.new_exiting.7
+    i32 3, label %dx.struct_exit.new_exiting.7
+    i32 5, label %dx.struct_exit.new_exiting.7
+  ], !dbg !31 ; line:23 col:5
+
+sw.epilog.7:                                      ; preds = %if.end.7
+  br label %dx.struct_exit.new_exiting.7
+
+dx.struct_exit.new_exiting.7:                     ; preds = %sw.epilog.7, %if.end.7, %if.end.7, %if.end.7, %if.end.7, %for.inc.6
+  %dx.struct_exit.prop.7 = phi i32 [ %do_discard.2.6, %sw.epilog.7 ], [ 0, %if.end.7 ], [ 0, %if.end.7 ], [ 0, %if.end.7 ], [ 0, %if.end.7 ], [ 0, %for.inc.6 ]
+  %do_discard.2.7 = phi i32 [ 1, %sw.epilog.7 ], [ 1, %if.end.7 ], [ 1, %if.end.7 ], [ 1, %if.end.7 ], [ 1, %if.end.7 ], [ %do_discard.2.6, %for.inc.6 ]
+  %g.2.i0.7 = phi float [ 0x3FF921FB60000000, %sw.epilog.7 ], [ 0x3FF921FB60000000, %if.end.7 ], [ 0x3FF921FB60000000, %if.end.7 ], [ 0x3FF921FB60000000, %if.end.7 ], [ 0x3FF921FB60000000, %if.end.7 ], [ %g.2.i0.6, %for.inc.6 ]
+  br i1 false, label %cleanup, label %for.inc.7
+
+for.inc.7:                                        ; preds = %dx.struct_exit.new_exiting.7
+  %cmp3.8 = fcmp fast une float %g.2.i0.7, 0.000000e+00, !dbg !29 ; line:19 col:13
+  br i1 %cmp3.8, label %dx.struct_exit.new_exiting.8, label %if.end.8, !dbg !30 ; line:19 col:9
+
+if.end.8:                                         ; preds = %for.inc.7
+  switch i32 8, label %sw.epilog.8 [
+    i32 1, label %dx.struct_exit.new_exiting.8
+    i32 2, label %dx.struct_exit.new_exiting.8
+    i32 3, label %dx.struct_exit.new_exiting.8
+    i32 5, label %dx.struct_exit.new_exiting.8
+  ], !dbg !31 ; line:23 col:5
+
+sw.epilog.8:                                      ; preds = %if.end.8
+  br label %dx.struct_exit.new_exiting.8
+
+dx.struct_exit.new_exiting.8:                     ; preds = %sw.epilog.8, %if.end.8, %if.end.8, %if.end.8, %if.end.8, %for.inc.7
+  %dx.struct_exit.prop.8 = phi i32 [ %do_discard.2.7, %sw.epilog.8 ], [ 0, %if.end.8 ], [ 0, %if.end.8 ], [ 0, %if.end.8 ], [ 0, %if.end.8 ], [ 0, %for.inc.7 ]
+  %do_discard.2.8 = phi i32 [ 1, %sw.epilog.8 ], [ 1, %if.end.8 ], [ 1, %if.end.8 ], [ 1, %if.end.8 ], [ 1, %if.end.8 ], [ %do_discard.2.7, %for.inc.7 ]
+  %g.2.i0.8 = phi float [ 0x3FF921FB60000000, %sw.epilog.8 ], [ 0x3FF921FB60000000, %if.end.8 ], [ 0x3FF921FB60000000, %if.end.8 ], [ 0x3FF921FB60000000, %if.end.8 ], [ 0x3FF921FB60000000, %if.end.8 ], [ %g.2.i0.7, %for.inc.7 ]
+  br i1 false, label %cleanup, label %for.inc.8
+
+for.inc.8:                                        ; preds = %dx.struct_exit.new_exiting.8
+  %cmp3.9 = fcmp fast une float %g.2.i0.8, 0.000000e+00, !dbg !29 ; line:19 col:13
+  br i1 %cmp3.9, label %dx.struct_exit.new_exiting.9, label %if.end.9, !dbg !30 ; line:19 col:9
+
+if.end.9:                                         ; preds = %for.inc.8
+  switch i32 9, label %sw.epilog.9 [
+    i32 1, label %dx.struct_exit.new_exiting.9
+    i32 2, label %dx.struct_exit.new_exiting.9
+    i32 3, label %dx.struct_exit.new_exiting.9
+    i32 5, label %dx.struct_exit.new_exiting.9
+  ], !dbg !31 ; line:23 col:5
+
+sw.epilog.9:                                      ; preds = %if.end.9
+  br label %dx.struct_exit.new_exiting.9
+
+dx.struct_exit.new_exiting.9:                     ; preds = %sw.epilog.9, %if.end.9, %if.end.9, %if.end.9, %if.end.9, %for.inc.8
+  %dx.struct_exit.prop.9 = phi i32 [ %do_discard.2.8, %sw.epilog.9 ], [ 0, %if.end.9 ], [ 0, %if.end.9 ], [ 0, %if.end.9 ], [ 0, %if.end.9 ], [ 0, %for.inc.8 ]
+  %do_discard.2.9 = phi i32 [ 1, %sw.epilog.9 ], [ 1, %if.end.9 ], [ 1, %if.end.9 ], [ 1, %if.end.9 ], [ 1, %if.end.9 ], [ %do_discard.2.8, %for.inc.8 ]
+  br i1 false, label %cleanup, label %for.inc.9
+
+for.inc.9:                                        ; preds = %dx.struct_exit.new_exiting.9
+  br label %cleanup
+}
+
+; Function Attrs: nounwind
+declare void @dx.op.storeOutput.f32(i32, i32, i32, i8, float) #0
+
+; Function Attrs: nounwind
+declare void @dx.op.discard(i32, i1) #0
+
+; Function Attrs: nounwind readonly
+declare %dx.types.ResRet.i32 @dx.op.rawBufferLoad.i32(i32, %dx.types.Handle, i32, i32, i8, i32) #1
+
+; Function Attrs: nounwind readonly
+declare %dx.types.Handle @dx.op.createHandleForLib.struct.ByteAddressBuffer(i32, %struct.ByteAddressBuffer) #1
+
+; Function Attrs: nounwind readnone
+declare %dx.types.Handle @dx.op.annotateHandle(i32, %dx.types.Handle, %dx.types.ResourceProperties) #2
+
+attributes #0 = { nounwind }
+attributes #1 = { nounwind readonly }
+attributes #2 = { nounwind readnone }
+
+!llvm.module.flags = !{!0}
+!pauseresume = !{!1}
+!llvm.ident = !{!2}
+!dx.version = !{!3}
+!dx.valver = !{!4}
+!dx.shaderModel = !{!5}
+!dx.resources = !{!6}
+!dx.typeAnnotations = !{!9, !12}
+!dx.entryPoints = !{!19}
+
+!0 = !{i32 2, !"Debug Info Version", i32 3}
+!1 = !{!"hlsl-dxilemit", !"hlsl-dxilload"}
+!2 = !{!"dxc(private) 1.8.0.4514 (d9bd2a706-dirty)"}
+!3 = !{i32 1, i32 6}
+!4 = !{i32 1, i32 8}
+!5 = !{!"ps", i32 6, i32 6}
+!6 = !{!7, null, null, null}
+!7 = !{!8}
+!8 = !{i32 0, %struct.ByteAddressBuffer* @"\01?g_buff@@3UByteAddressBuffer@@A", !"g_buff", i32 0, i32 0, i32 1, i32 11, i32 0, null}
+!9 = !{i32 0, %struct.retval undef, !10}
+!10 = !{i32 16, !11}
+!11 = !{i32 6, !"value", i32 3, i32 0, i32 4, !"SV_Target0", i32 7, i32 9}
+!12 = !{i32 1, void (<4 x float>*)* @main, !13}
+!13 = !{!14, !16}
+!14 = !{i32 0, !15, !15}
+!15 = !{}
+!16 = !{i32 1, !17, !18}
+!17 = !{i32 4, !"SV_Target0", i32 7, i32 9}
+!18 = !{i32 0}
+!19 = !{void (<4 x float>*)* @main, !"main", !20, !6, null}
+!20 = !{null, !21, null}
+!21 = !{!22}
+!22 = !{i32 0, !"SV_Target", i8 9, i8 16, !18, i8 0, i32 1, i8 4, i32 0, i8 0, null}
+!23 = !DILocation(line: 15, column: 22, scope: !24)
+!24 = !DISubprogram(name: "main", scope: !25, file: !25, line: 14, type: !26, isLocal: false, isDefinition: true, scopeLine: 14, flags: DIFlagPrototyped, isOptimized: false, function: void (<4 x float>*)* @main)
+!25 = !DIFile(filename: "/home/amaiorano/src/external/DirectXShaderCompiler/tools/clang/test/DXC/Passes/DxilRemoveDeadBlocks/switch-with-multiple-same-successor.hlsl", directory: "")
+!26 = !DISubroutineType(types: !15)
+!27 = !DILocation(line: 15, column: 14, scope: !24)
+!28 = !DILocation(line: 18, column: 3, scope: !24)
+!29 = !DILocation(line: 19, column: 13, scope: !24)
+!30 = !DILocation(line: 19, column: 9, scope: !24)
+!31 = !DILocation(line: 23, column: 5, scope: !24)
+!32 = !DILocation(line: 49, column: 7, scope: !24)
+!33 = !DILocation(line: 49, column: 19, scope: !24)
+!34 = !DILocation(line: 51, column: 3, scope: !24)
+!35 = !DILocation(line: 53, column: 18, scope: !24)
+!36 = !DILocation(line: 54, column: 1, scope: !24)
