Browse Source

chore: [29-x-y] cherry-pick 3 changes from 0-M126 (#42603)

* chore: [29-x-y] cherry-pick 3 changes from 0-M126

* 33051b084850 from DirectXShaderCompiler
* b845fed99111 from DirectXShaderCompiler
* 9c6534f82db3 from dawn

* chore: update patches

---------

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Pedro Pontes 10 months ago
parent
commit
8ca9e1543d

+ 2 - 0
patches/DirectXShaderCompiler/.patches

@@ -5,3 +5,5 @@ cherry-pick-2a434fd0af6b.patch
 cherry-pick-867c1001637e.patch
 cherry-pick-0b785e88fefa.patch
 cherry-pick-511cfef8e050.patch
+cherry-pick-33051b084850.patch
+cherry-pick-b845fed99111.patch

+ 332 - 0
patches/DirectXShaderCompiler/cherry-pick-33051b084850.patch

@@ -0,0 +1,332 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Antonio Maiorano <[email protected]>
+Date: Mon, 10 Jun 2024 10:52:30 -0400
+Subject: Loop exit restructurizer: don't iterate over uses while mutating them
+ (#6644)
+
+The SkipBlockWithBranch function does the following:
+- Splits the block into three blocks with an if-then-endif structure.
+- Moves most instructions from the original block into the "then" block
+- If any of those values are used outside the original block, they are
+propagated through newly-constructed phis in the 'endif' block.
+
+This algorithm had a bug where the uses of a value were being scanned
+while the uses were also being updated. In some cases a downstream
+out-of-block use could be skipped. That results in an invalid module
+because now the original definition is now in the 'then' block, which
+does not dominate the downstream out-of-block use.
+
+Add a test that demonstrates the problem.
+
+Bug: chromium:339171223
+Change-Id: Ia34fd7a2fe84de635289f7499772d11866a28e24
+Reviewed-on: https://chromium-review.googlesource.com/c/external/github.com/microsoft/DirectXShaderCompiler/+/5615350
+Reviewed-by: James Price <[email protected]>
+Reviewed-by: dan sinclair <[email protected]>
+
+diff --git a/lib/Transforms/Scalar/DxilRemoveUnstructuredLoopExits.cpp b/lib/Transforms/Scalar/DxilRemoveUnstructuredLoopExits.cpp
+index ef6718f0f22ee33e3f16f9801a64c1a6fb6c653a..70e6ccd8ddbaeabdb469710ad8529933f0286abd 100644
+--- a/lib/Transforms/Scalar/DxilRemoveUnstructuredLoopExits.cpp
++++ b/lib/Transforms/Scalar/DxilRemoveUnstructuredLoopExits.cpp
+@@ -322,24 +322,26 @@ static void SkipBlockWithBranch(BasicBlock *bb, Value *cond, Loop *L,
+   BranchInst::Create(end, body, cond, bb);
+ 
+   for (Instruction &inst : *body) {
+-    PHINode *phi = nullptr;
+ 
+     // For each user that's outside of 'body', replace its use of 'inst' with a
+     // phi created in 'end'
+-    for (auto it = inst.user_begin(); it != inst.user_end();) {
+-      Instruction *user_inst = cast<Instruction>(*(it++));
+-      if (user_inst == phi)
+-        continue;
++    SmallPtrSet<Instruction *, 8> users_in_other_blocks;
++    for (auto *user : inst.users()) {
++      Instruction *user_inst = cast<Instruction>(user);
+       if (user_inst->getParent() != body) {
+-        if (!phi) {
+-          phi = PHINode::Create(inst.getType(), 2, "", &*end->begin());
+-          phi->addIncoming(GetDefaultValue(inst.getType()), bb);
+-          phi->addIncoming(&inst, body);
+-        }
++        users_in_other_blocks.insert(user_inst);
++      }
++    }
++    if (users_in_other_blocks.size() > 0) {
++      auto *phi = PHINode::Create(inst.getType(), 2, "", &*end->begin());
++      phi->addIncoming(GetDefaultValue(inst.getType()), bb);
++      phi->addIncoming(&inst, body);
++
++      for (auto *user_inst : users_in_other_blocks) {
+         user_inst->replaceUsesOfWith(&inst, phi);
+       }
+-    } // For each user of inst of body
+-  }   // For each inst in body
++    }
++  } // For each inst in body
+ 
+   L->addBasicBlockToLoop(body, *LI);
+   L->addBasicBlockToLoop(end, *LI);
+diff --git a/tools/clang/test/DXC/Passes/DxilRemoveUnstructuredLoopExits/struct_exit_wrap_value_iteration_bug.ll b/tools/clang/test/DXC/Passes/DxilRemoveUnstructuredLoopExits/struct_exit_wrap_value_iteration_bug.ll
+new file mode 100644
+index 0000000000000000000000000000000000000000..ee912c929bdc0424959a29d16c3d5c64f885f809
+--- /dev/null
++++ b/tools/clang/test/DXC/Passes/DxilRemoveUnstructuredLoopExits/struct_exit_wrap_value_iteration_bug.ll
+@@ -0,0 +1,257 @@
++; RUN: %dxopt %s -hlsl-passes-resume -loop-unroll,StructurizeLoopExits=1 -S | FileCheck %s
++
++; The Loop exit structurizer will wrap the definition of %DerivFineX3 in a conditional block.
++; Its value will later be propagated into a phi, and that phi replaces all further uses
++; of %DerivFineX3.
++;
++; Tests that a bug is fixed where the code used to iterate through the uses of a value
++; while also updating those uses.  The old code would fail to update the definition
++; of %g.i.2.i3 and the result would be an invalid module: %DerivFineX3 would not dominate
++; all its uses.
++
++
++; CHECK: define void @main
++; CHECK-NOT:  %DerivFineX3
++; CHECK:  "\01?f@@YAXXZ.exit.i":
++; CHECK-NEXT:  br i1 true, label %dx.struct_exit.cond_end, label %dx.struct_exit.cond_body
++
++; CHECK: dx.struct_exit.cond_body:
++; CHECK:  %DerivFineX3 = call
++; CHECK:  br label %dx.struct_exit.cond_end
++
++; CHECK: dx.struct_exit.cond_end:
++; CHECK:  = phi {{.*}} %DerivFineX3
++; CHECK:  br
++; CHECK-NOT:  %DerivFineX3
++; CHECK: ret void
++
++
++;
++;
++; void f() {
++;   int l_1 = 10;
++;   for (int l = 0, l_2 = 0; l < 5 && l_2 < 1; l++, l_2++) {
++;     while (1 < l_1) { }
++;   }
++; }
++;
++;
++; struct tint_symbol {
++;   float4 value : SV_Target0;
++; };
++;
++; float4 main_inner() {
++;   float4 g = float4(0.0f, 0.0f, 0.0f, 0.0f);
++;   bool2 true2 = (true).xx;
++;   uint2 _e8 = (0u).xx;
++;   do {
++;     if (_e8.x != 2u) {
++;       f();
++;       float4 _e15 = ddx_fine(g);
++;       if (_e8[_e8.x] == 2u) {
++;         g = _e15;
++;       } else {
++;         f();
++;       }
++;       switch(_e8.x) {
++;         case 3u: {
++;           break;
++;         }
++;         case 2u: {
++;           g = _e15;
++;           break;
++;         }
++;         default: {
++;           g = _e15;
++;         }
++;       }
++;       f();
++;     }
++;  } while(!all(true2));
++;   return g;
++;}
++;
++;tint_symbol main() {
++;  float4 inner_result = main_inner();
++;  tint_symbol wrapper_result = (tint_symbol)0;
++;  wrapper_result.value = inner_result;
++;  return wrapper_result;
++;}
++
++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.tint_symbol = type { <4 x float> }
++
++; Function Attrs: nounwind
++define void @main(<4 x float>* noalias) #0 {
++entry:
++  %1 = alloca [2 x i32], align 4
++  %2 = getelementptr inbounds [2 x i32], [2 x i32]* %1, i32 0, i32 0, !dbg !20 ; line:17 col:9
++  store i32 0, i32* %2, align 4, !dbg !20 ; line:17 col:9
++  %3 = getelementptr inbounds [2 x i32], [2 x i32]* %1, i32 0, i32 1, !dbg !20 ; line:17 col:9
++  store i32 0, i32* %3, align 4, !dbg !20 ; line:17 col:9
++  br label %do.body.i, !dbg !26 ; line:18 col:3
++
++do.body.i:                                        ; preds = %do.cond.i, %entry
++  %g.i.0.i0 = phi float [ 0.000000e+00, %entry ], [ %g.i.3.i0, %do.cond.i ]
++  %g.i.0.i1 = phi float [ 0.000000e+00, %entry ], [ %g.i.3.i1, %do.cond.i ]
++  %g.i.0.i2 = phi float [ 0.000000e+00, %entry ], [ %g.i.3.i2, %do.cond.i ]
++  %g.i.0.i3 = phi float [ 0.000000e+00, %entry ], [ %g.i.3.i3, %do.cond.i ]
++  %4 = getelementptr inbounds [2 x i32], [2 x i32]* %1, i32 0, i32 0, !dbg !27 ; line:19 col:9
++  %5 = load i32, i32* %4, align 4, !dbg !27 ; line:19 col:9
++  %cmp.i = icmp ne i32 %5, 2, !dbg !28 ; line:19 col:15
++  br i1 %cmp.i, label %for.cond.i.i, label %do.cond.i, !dbg !27 ; line:19 col:9
++
++for.cond.i.i:                                     ; preds = %do.body.i
++  br i1 true, label %while.cond.i.i.preheader, label %"\01?f@@YAXXZ.exit.i", !dbg !29 ; line:4 col:3
++
++while.cond.i.i.preheader:                         ; preds = %for.cond.i.i
++  br label %while.cond.i.i, !dbg !32 ; line:5 col:5
++
++while.cond.i.i:                                   ; preds = %while.cond.i.i.preheader, %while.cond.i.i
++  br label %while.cond.i.i, !dbg !32 ; line:5 col:5
++
++"\01?f@@YAXXZ.exit.i":                            ; preds = %for.cond.i.i
++  %DerivFineX = call float @dx.op.unary.f32(i32 85, float %g.i.0.i0), !dbg !33 ; line:21 col:21  ; DerivFineX(value)
++  %DerivFineX1 = call float @dx.op.unary.f32(i32 85, float %g.i.0.i1), !dbg !33 ; line:21 col:21  ; DerivFineX(value)
++  %DerivFineX2 = call float @dx.op.unary.f32(i32 85, float %g.i.0.i2), !dbg !33 ; line:21 col:21  ; DerivFineX(value)
++  %DerivFineX3 = call float @dx.op.unary.f32(i32 85, float %g.i.0.i3), !dbg !33 ; line:21 col:21  ; DerivFineX(value)
++  %6 = getelementptr inbounds [2 x i32], [2 x i32]* %1, i32 0, i32 0, !dbg !34 ; line:22 col:15
++  %7 = load i32, i32* %6, align 4, !dbg !34 ; line:22 col:15
++  %8 = getelementptr [2 x i32], [2 x i32]* %1, i32 0, i32 %7, !dbg !35 ; line:22 col:11
++  %9 = load i32, i32* %8, !dbg !35, !tbaa !36 ; line:22 col:11
++  %cmp6.i = icmp eq i32 %9, 2, !dbg !40 ; line:22 col:22
++  br i1 %cmp6.i, label %if.end.i, label %for.cond.i.19.i, !dbg !35 ; line:22 col:11
++
++for.cond.i.19.i:                                  ; preds = %"\01?f@@YAXXZ.exit.i"
++  br i1 true, label %while.cond.i.24.i.preheader, label %if.end.i, !dbg !41 ; line:4 col:3
++
++while.cond.i.24.i.preheader:                      ; preds = %for.cond.i.19.i
++  br label %while.cond.i.24.i, !dbg !43 ; line:5 col:5
++
++while.cond.i.24.i:                                ; preds = %while.cond.i.24.i.preheader, %while.cond.i.24.i
++  br label %while.cond.i.24.i, !dbg !43 ; line:5 col:5
++
++if.end.i:                                         ; preds = %for.cond.i.19.i, %"\01?f@@YAXXZ.exit.i"
++  %g.i.1.i0 = phi float [ %DerivFineX, %"\01?f@@YAXXZ.exit.i" ], [ %g.i.0.i0, %for.cond.i.19.i ]
++  %g.i.1.i1 = phi float [ %DerivFineX1, %"\01?f@@YAXXZ.exit.i" ], [ %g.i.0.i1, %for.cond.i.19.i ]
++  %g.i.1.i2 = phi float [ %DerivFineX2, %"\01?f@@YAXXZ.exit.i" ], [ %g.i.0.i2, %for.cond.i.19.i ]
++  %g.i.1.i3 = phi float [ %DerivFineX3, %"\01?f@@YAXXZ.exit.i" ], [ %g.i.0.i3, %for.cond.i.19.i ]
++  %10 = getelementptr inbounds [2 x i32], [2 x i32]* %1, i32 0, i32 0, !dbg !44 ; line:27 col:14
++  %11 = load i32, i32* %10, align 4, !dbg !44 ; line:27 col:14
++  switch i32 %11, label %sw.default.i [
++    i32 3, label %for.cond.i.5.i
++    i32 2, label %sw.bb.10.i
++  ], !dbg !45 ; line:27 col:7
++
++sw.bb.10.i:                                       ; preds = %if.end.i
++  br label %for.cond.i.5.i, !dbg !46 ; line:33 col:11
++
++sw.default.i:                                     ; preds = %if.end.i
++  br label %for.cond.i.5.i, !dbg !47 ; line:38 col:7
++
++for.cond.i.5.i:                                   ; preds = %if.end.i, %sw.bb.10.i, %sw.default.i
++  %g.i.2.i0 = phi float [ %DerivFineX, %sw.default.i ], [ %DerivFineX, %sw.bb.10.i ], [ %g.i.1.i0, %if.end.i ]
++  %g.i.2.i1 = phi float [ %DerivFineX1, %sw.default.i ], [ %DerivFineX1, %sw.bb.10.i ], [ %g.i.1.i1, %if.end.i ]
++  %g.i.2.i2 = phi float [ %DerivFineX2, %sw.default.i ], [ %DerivFineX2, %sw.bb.10.i ], [ %g.i.1.i2, %if.end.i ]
++  %g.i.2.i3 = phi float [ %DerivFineX3, %sw.default.i ], [ %DerivFineX3, %sw.bb.10.i ], [ %g.i.1.i3, %if.end.i ]
++  br i1 true, label %while.cond.i.10.i.preheader, label %do.cond.i, !dbg !48 ; line:4 col:3
++
++while.cond.i.10.i.preheader:                      ; preds = %for.cond.i.5.i
++  br label %while.cond.i.10.i, !dbg !50 ; line:5 col:5
++
++while.cond.i.10.i:                                ; preds = %while.cond.i.10.i.preheader, %while.cond.i.10.i
++  br label %while.cond.i.10.i, !dbg !50 ; line:5 col:5
++
++do.cond.i:                                        ; preds = %for.cond.i.5.i, %do.body.i
++  %g.i.3.i0 = phi float [ %g.i.0.i0, %do.body.i ], [ %g.i.2.i0, %for.cond.i.5.i ]
++  %g.i.3.i1 = phi float [ %g.i.0.i1, %do.body.i ], [ %g.i.2.i1, %for.cond.i.5.i ]
++  %g.i.3.i2 = phi float [ %g.i.0.i2, %do.body.i ], [ %g.i.2.i2, %for.cond.i.5.i ]
++  %g.i.3.i3 = phi float [ %g.i.0.i3, %do.body.i ], [ %g.i.2.i3, %for.cond.i.5.i ]
++  br i1 false, label %do.body.i, label %"\01?main_inner@@YA?AV?$vector@M$03@@XZ.exit", !dbg !51 ; line:41 col:3
++
++"\01?main_inner@@YA?AV?$vector@M$03@@XZ.exit":    ; preds = %do.cond.i
++  %g.i.3.i3.lcssa = phi float [ %g.i.3.i3, %do.cond.i ]
++  %g.i.3.i2.lcssa = phi float [ %g.i.3.i2, %do.cond.i ]
++  %g.i.3.i1.lcssa = phi float [ %g.i.3.i1, %do.cond.i ]
++  %g.i.3.i0.lcssa = phi float [ %g.i.3.i0, %do.cond.i ]
++  call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 0, float %g.i.3.i0.lcssa), !dbg !52 ; line:49 col:10  ; StoreOutput(outputSigId,rowIndex,colIndex,value)
++  call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 1, float %g.i.3.i1.lcssa), !dbg !52 ; line:49 col:10  ; StoreOutput(outputSigId,rowIndex,colIndex,value)
++  call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 2, float %g.i.3.i2.lcssa), !dbg !52 ; line:49 col:10  ; StoreOutput(outputSigId,rowIndex,colIndex,value)
++  call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 3, float %g.i.3.i3.lcssa), !dbg !52 ; line:49 col:10  ; StoreOutput(outputSigId,rowIndex,colIndex,value)
++  ret void, !dbg !53 ; line:49 col:3
++}
++
++; Function Attrs: nounwind
++declare void @dx.op.storeOutput.f32(i32, i32, i32, i8, float) #0
++
++; Function Attrs: nounwind readnone
++declare float @dx.op.unary.f32(i32, float) #1
++
++attributes #0 = { nounwind }
++attributes #1 = { nounwind readnone }
++
++!llvm.module.flags = !{!0}
++!pauseresume = !{!1}
++!llvm.ident = !{!2}
++!dx.version = !{!3}
++!dx.valver = !{!4}
++!dx.shaderModel = !{!5}
++!dx.typeAnnotations = !{!6, !9}
++!dx.entryPoints = !{!16}
++
++!0 = !{i32 2, !"Debug Info Version", i32 3}
++!1 = !{!"hlsl-dxilemit", !"hlsl-dxilload"}
++!2 = !{!"dxc(private) 1.8.0.14549 (main, 0781ded87-dirty)"}
++!3 = !{i32 1, i32 0}
++!4 = !{i32 1, i32 8}
++!5 = !{!"ps", i32 6, i32 0}
++!6 = !{i32 0, %struct.tint_symbol undef, !7}
++!7 = !{i32 16, !8}
++!8 = !{i32 6, !"value", i32 3, i32 0, i32 4, !"SV_Target0", i32 7, i32 9}
++!9 = !{i32 1, void (<4 x float>*)* @main, !10}
++!10 = !{!11, !13}
++!11 = !{i32 0, !12, !12}
++!12 = !{}
++!13 = !{i32 1, !14, !15}
++!14 = !{i32 4, !"SV_Target0", i32 7, i32 9}
++!15 = !{i32 0}
++!16 = !{void (<4 x float>*)* @main, !"main", !17, null, null}
++!17 = !{null, !18, null}
++!18 = !{!19}
++!19 = !{i32 0, !"SV_Target", i8 9, i8 16, !15, i8 0, i32 1, i8 4, i32 0, i8 0, null}
++!20 = !DILocation(line: 17, column: 9, scope: !21, inlinedAt: !24)
++!21 = !DISubprogram(name: "main_inner", scope: !22, file: !22, line: 14, type: !23, isLocal: false, isDefinition: true, scopeLine: 14, flags: DIFlagPrototyped, isOptimized: false)
++!22 = !DIFile(filename: "s2.hlsl", directory: "")
++!23 = !DISubroutineType(types: !12)
++!24 = distinct !DILocation(line: 46, column: 25, scope: !25)
++!25 = !DISubprogram(name: "main", scope: !22, file: !22, line: 45, type: !23, isLocal: false, isDefinition: true, scopeLine: 45, flags: DIFlagPrototyped, isOptimized: false, function: void (<4 x float>*)* @main)
++!26 = !DILocation(line: 18, column: 3, scope: !21, inlinedAt: !24)
++!27 = !DILocation(line: 19, column: 9, scope: !21, inlinedAt: !24)
++!28 = !DILocation(line: 19, column: 15, scope: !21, inlinedAt: !24)
++!29 = !DILocation(line: 4, column: 3, scope: !30, inlinedAt: !31)
++!30 = !DISubprogram(name: "f", scope: !22, file: !22, line: 2, type: !23, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: false)
++!31 = distinct !DILocation(line: 20, column: 7, scope: !21, inlinedAt: !24)
++!32 = !DILocation(line: 5, column: 5, scope: !30, inlinedAt: !31)
++!33 = !DILocation(line: 21, column: 21, scope: !21, inlinedAt: !24)
++!34 = !DILocation(line: 22, column: 15, scope: !21, inlinedAt: !24)
++!35 = !DILocation(line: 22, column: 11, scope: !21, inlinedAt: !24)
++!36 = !{!37, !37, i64 0}
++!37 = !{!"int", !38, i64 0}
++!38 = !{!"omnipotent char", !39, i64 0}
++!39 = !{!"Simple C/C++ TBAA"}
++!40 = !DILocation(line: 22, column: 22, scope: !21, inlinedAt: !24)
++!41 = !DILocation(line: 4, column: 3, scope: !30, inlinedAt: !42)
++!42 = distinct !DILocation(line: 25, column: 9, scope: !21, inlinedAt: !24)
++!43 = !DILocation(line: 5, column: 5, scope: !30, inlinedAt: !42)
++!44 = !DILocation(line: 27, column: 14, scope: !21, inlinedAt: !24)
++!45 = !DILocation(line: 27, column: 7, scope: !21, inlinedAt: !24)
++!46 = !DILocation(line: 33, column: 11, scope: !21, inlinedAt: !24)
++!47 = !DILocation(line: 38, column: 7, scope: !21, inlinedAt: !24)
++!48 = !DILocation(line: 4, column: 3, scope: !30, inlinedAt: !49)
++!49 = distinct !DILocation(line: 39, column: 7, scope: !21, inlinedAt: !24)
++!50 = !DILocation(line: 5, column: 5, scope: !30, inlinedAt: !49)
++!51 = !DILocation(line: 41, column: 3, scope: !21, inlinedAt: !24)
++!52 = !DILocation(line: 49, column: 10, scope: !25)
++!53 = !DILocation(line: 49, column: 3, scope: !25)

+ 294 - 0
patches/DirectXShaderCompiler/cherry-pick-b845fed99111.patch

@@ -0,0 +1,294 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Natalie Chouinard <[email protected]>
+Date: Mon, 10 Jun 2024 18:21:40 +0000
+Subject: Fix LoopDeletion incorrectly updating PHI with multiple duplicate
+ inputs (#6643)
+
+LoopDeletion was incorrectly updating PHI nodes in the target block when
+it had duplicate input edges. This happens, for example, when deleting a
+loop that uses a switch with multiple cases that exit the same way.
+
+After determining that this was the bug, I found this fix in LLVM:
+https://reviews.llvm.org/D34516 and applied it here.
+
+Bug: 340196361
+Change-Id: I98b150bb9a164466eb84dd3d46f720d5d92ef909
+Reviewed-on: https://chromium-review.googlesource.com/c/external/github.com/microsoft/DirectXShaderCompiler/+/5616791
+Reviewed-by: Antonio Maiorano <[email protected]>
+Reviewed-by: dan sinclair <[email protected]>
+
+diff --git a/lib/Transforms/Scalar/LoopDeletion.cpp b/lib/Transforms/Scalar/LoopDeletion.cpp
+index 6c2c1d60548f5a8a7939fee70728e8a34572b648..6cd1fba7c085b6d61dcb23b073358fc4c798e099 100644
+--- a/lib/Transforms/Scalar/LoopDeletion.cpp
++++ b/lib/Transforms/Scalar/LoopDeletion.cpp
+@@ -195,15 +195,29 @@ bool LoopDeletion::runOnLoop(Loop *L, LPPassManager &LPM) {
+ 
+   // Rewrite phis in the exit block to get their inputs from
+   // the preheader instead of the exiting block.
+-  BasicBlock *exitingBlock = exitingBlocks[0];
+   BasicBlock::iterator BI = exitBlock->begin();
+   while (PHINode *P = dyn_cast<PHINode>(BI)) {
+-    int j = P->getBasicBlockIndex(exitingBlock);
+-    assert(j >= 0 && "Can't find exiting block in exit block's phi node!");
+-    P->setIncomingBlock(j, preheader);
+-    for (unsigned i = 1; i < exitingBlocks.size(); ++i)
+-      P->removeIncomingValue(exitingBlocks[i]);
++    // HLSL Change begin - apply https://reviews.llvm.org/D34516
++    // Set the zero'th element of Phi to be from the preheader and remove all
++    // other incoming values. Given the loop has dedicated exits, all other
++    // incoming values must be from the exiting blocks.
++    int PredIndex = 0;
++    P->setIncomingBlock(PredIndex, preheader);
++    // Removes all incoming values from all other exiting blocks (including
++    // duplicate values from an exiting block).
++    // Nuke all entries except the zero'th entry which is the preheader entry.
++    // NOTE! We need to remove Incoming Values in the reverse order as done
++    // below, to keep the indices valid for deletion (removeIncomingValues
++    // updates getNumIncomingValues and shifts all values down into the operand
++    // being deleted).
++    for (unsigned i = 0, e = P->getNumIncomingValues() - 1; i != e; ++i)
++      P->removeIncomingValue(e - i, false);
++
++    assert((P->getNumIncomingValues() == 1 &&
++            P->getIncomingBlock(PredIndex) == preheader) &&
++           "Should have exactly one value and that's from the preheader!");
+     ++BI;
++    // HLSL Change end
+   }
+ 
+   // Update the dominator tree and remove the instructions and blocks that will
+diff --git a/tools/clang/test/DXC/Passes/DxilLoopDeletion/dxil-loop-deletion-phi-with-duplicate-preds.ll b/tools/clang/test/DXC/Passes/DxilLoopDeletion/dxil-loop-deletion-phi-with-duplicate-preds.ll
+new file mode 100644
+index 0000000000000000000000000000000000000000..62736bf2934a5db67ee75386431498f49e101f49
+--- /dev/null
++++ b/tools/clang/test/DXC/Passes/DxilLoopDeletion/dxil-loop-deletion-phi-with-duplicate-preds.ll
+@@ -0,0 +1,229 @@
++; RUN: %dxopt %s -hlsl-passes-resume -dxil-loop-deletion,NoSink=0 -S | FileCheck %s
++
++; This test was generated from the following HLSL:
++;
++;  cbuffer cbuffer_g : register(b0) {
++;    uint4 gu4[1];
++;  };
++;
++;  float4 f() {
++;    float4 r = float4(0.0f, 0.0f, 0.0f, 0.0f);
++;    int i = 0;
++;    int j = 0;
++;    while (true) {
++;      float a = asfloat(gu4[0].y);
++;      int ai = int(a);
++;      bool b = (j < ai);
++;      if (j >= ai) {
++;        break;
++;      }
++;      bool c = (i > 0);
++;      if (c) {
++;        break;
++;      } else {
++;        bool3 b3 = bool3(b.xxx);
++;        if (b3[i]) {
++;          switch(i) {
++;            case 0: return r;
++;            case -1: return r;
++;          }
++;          if (c) {
++;            break;
++;          }
++;        } else {
++;          r = float4(0.0f, 0.0f, 0.0f, a);
++;        }
++;      }
++;      i = j;
++;      j = (j + 1);
++;    }
++;    r = (0.0f).xxxx;
++;    return r;
++;  }
++;
++;  struct return_val {
++;    float4 value : SV_Target0;
++;  };
++;
++;  return_val main() {
++;    float4 inner_result = f();
++;    return_val wrapper_result = (return_val)0;
++;    wrapper_result.value = inner_result;
++;    return wrapper_result;
++;  }
++;
++; When compiling the above with dxc, ASAN reported a use-after-free in simplifycfg,
++; which originated from a delete during the dxil-loop-deletion pass. This was due
++; to a bug in LoopDeletion::runOnLoop that did not properly handle updated PHIs
++; with duplicate input preds. After this test runs, the loop should be deleted,
++; and the program optimized to simply write out 0s to the cbuffer.
++
++; CHECK: define void @main
++; CHECK-NEXT: entry:
++; CHECK-NEXT:  call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 0, float 0.000000e+00)
++; CHECK-NEXT:  call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 1, float 0.000000e+00)
++; CHECK-NEXT:  call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 2, float 0.000000e+00)
++; CHECK-NEXT:  call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 3, float 0.000000e+00)
++; CHECK-NEXT:  ret void
++
++;
++; Output signature:
++;
++; Name                 Index             InterpMode DynIdx
++; -------------------- ----- ---------------------- ------
++; SV_Target                0
++;
++; Buffer Definitions:
++;
++; cbuffer cbuffer_g
++; {
++;
++;   struct cbuffer_g
++;   {
++;
++;       uint4 gu4[1];                                 ; Offset:    0
++;
++;   } cbuffer_g;                                      ; Offset:    0 Size:    16
++;
++; }
++;
++;
++; Resource Bindings:
++;
++; Name                                 Type  Format         Dim      ID      HLSL Bind  Count
++; ------------------------------ ---------- ------- ----------- ------- -------------- ------
++; cbuffer_g                         cbuffer      NA          NA     CB0            cb0     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"
++
++%cbuffer_g = type { [1 x <4 x i32>] }
++%dx.types.Handle = type { i8* }
++%dx.types.ResourceProperties = type { i32, i32 }
++%dx.types.CBufRet.i32 = type { i32, i32, i32, i32 }
++%struct.return_val = type { <4 x float> }
++
++@cbuffer_g = external constant %cbuffer_g
[email protected] = internal unnamed_addr constant [3 x i32] [i32 1, i32 1, i32 1]
[email protected] = appending global [1 x i8*] [i8* bitcast (%cbuffer_g* @cbuffer_g to i8*)], section "llvm.metadata"
++
++; Function Attrs: nounwind readnone
++declare %dx.types.Handle @"dx.hl.createhandle..%dx.types.Handle (i32, %cbuffer_g*, i32)"(i32, %cbuffer_g*, i32) #0
++
++; Function Attrs: nounwind readnone
++declare %dx.types.Handle @"dx.hl.annotatehandle..%dx.types.Handle (i32, %dx.types.Handle, %dx.types.ResourceProperties, %cbuffer_g)"(i32, %dx.types.Handle, %dx.types.ResourceProperties, %cbuffer_g) #0
++
++; Function Attrs: nounwind
++define void @main(<4 x float>* noalias nocapture readnone) #1 {
++entry:
++  %1 = load %cbuffer_g, %cbuffer_g* @cbuffer_g, align 4, !dbg !25 ; line:45 col:25
++  %cbuffer_g = call %dx.types.Handle @dx.op.createHandleForLib.cbuffer_g(i32 160, %cbuffer_g %1), !dbg !25 ; line:45 col:25  ; CreateHandleForLib(Resource)
++  %2 = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle %cbuffer_g, %dx.types.ResourceProperties { i32 13, i32 16 }), !dbg !25 ; line:45 col:25  ; AnnotateHandle(res,props)  resource: CBuffer
++  %3 = call %dx.types.CBufRet.i32 @dx.op.cbufferLoadLegacy.i32(i32 59, %dx.types.Handle %2, i32 0), !dbg !29 ; line:10 col:23  ; CBufferLoadLegacy(handle,regIndex)
++  %4 = extractvalue %dx.types.CBufRet.i32 %3, 1, !dbg !29 ; line:10 col:23
++  %5 = bitcast i32 %4 to float, !dbg !32 ; line:10 col:15
++  %conv.i.6 = fptosi float %5 to i32, !dbg !33 ; line:11 col:18
++  %cmp1.i.8 = icmp sgt i32 %conv.i.6, 0, !dbg !34 ; line:13 col:11
++  br i1 %cmp1.i.8, label %if.end.i, label %"\01?f@@YA?AV?$vector@M$03@@XZ.exit", !dbg !35 ; line:13 col:9
++
++if.end.i:                                         ; preds = %entry, %if.end.19.i
++  %6 = phi float [ %9, %if.end.19.i ], [ %5, %entry ]
++  %j.i.011 = phi i32 [ %add.i, %if.end.19.i ], [ 0, %entry ]
++  %r.i.0.i310 = phi float [ %r.i.0.i310, %if.end.19.i ], [ 0.000000e+00, %entry ]
++  %i.i.09 = phi i32 [ %j.i.011, %if.end.19.i ], [ 0, %entry ]
++  %cmp4.i = icmp sgt i32 %i.i.09, 0, !dbg !36 ; line:16 col:17
++  br i1 %cmp4.i, label %"\01?f@@YA?AV?$vector@M$03@@XZ.exit", label %if.then.12.i, !dbg !37 ; line:17 col:9
++
++if.then.12.i:                                     ; preds = %if.end.i
++  switch i32 %i.i.09, label %if.end.19.i [
++    i32 0, label %"\01?f@@YA?AV?$vector@M$03@@XZ.exit"
++    i32 -1, label %"\01?f@@YA?AV?$vector@M$03@@XZ.exit"
++  ], !dbg !38 ; line:22 col:9
++
++if.end.19.i:                                      ; preds = %if.then.12.i
++  %add.i = add nuw nsw i32 %j.i.011, 1, !dbg !39 ; line:34 col:12
++  %7 = call %dx.types.CBufRet.i32 @dx.op.cbufferLoadLegacy.i32(i32 59, %dx.types.Handle %2, i32 0), !dbg !29 ; line:10 col:23  ; CBufferLoadLegacy(handle,regIndex)
++  %8 = extractvalue %dx.types.CBufRet.i32 %7, 1, !dbg !29 ; line:10 col:23
++  %9 = bitcast i32 %8 to float, !dbg !32 ; line:10 col:15
++  %conv.i = fptosi float %9 to i32, !dbg !33 ; line:11 col:18
++  %cmp.i = icmp slt i32 %add.i, %conv.i, !dbg !40 ; line:12 col:17
++  br i1 %cmp.i, label %if.end.i, label %"\01?f@@YA?AV?$vector@M$03@@XZ.exit", !dbg !35 ; line:13 col:9
++
++"\01?f@@YA?AV?$vector@M$03@@XZ.exit":             ; preds = %if.then.12.i, %if.then.12.i, %if.end.i, %if.end.19.i, %entry
++  %retval.i.0.i3 = phi float [ 0.000000e+00, %entry ], [ %r.i.0.i310, %if.then.12.i ], [ %r.i.0.i310, %if.then.12.i ], [ 0.000000e+00, %if.end.i ], [ 0.000000e+00, %if.end.19.i ]
++  call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 0, float 0.000000e+00), !dbg !41 ; line:48 col:10  ; StoreOutput(outputSigId,rowIndex,colIndex,value)
++  call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 1, float 0.000000e+00), !dbg !41 ; line:48 col:10  ; StoreOutput(outputSigId,rowIndex,colIndex,value)
++  call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 2, float 0.000000e+00), !dbg !41 ; line:48 col:10  ; StoreOutput(outputSigId,rowIndex,colIndex,value)
++  call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 3, float %retval.i.0.i3), !dbg !41 ; line:48 col:10  ; StoreOutput(outputSigId,rowIndex,colIndex,value)
++  ret void, !dbg !42 ; line:48 col:3
++}
++
++; Function Attrs: nounwind
++declare void @dx.op.storeOutput.f32(i32, i32, i32, i8, float) #1
++
++; Function Attrs: nounwind readonly
++declare %dx.types.CBufRet.i32 @dx.op.cbufferLoadLegacy.i32(i32, %dx.types.Handle, i32) #2
++
++; Function Attrs: nounwind readonly
++declare %dx.types.Handle @dx.op.createHandleForLib.cbuffer_g(i32, %cbuffer_g) #2
++
++; Function Attrs: nounwind readnone
++declare %dx.types.Handle @dx.op.annotateHandle(i32, %dx.types.Handle, %dx.types.ResourceProperties) #0
++
++attributes #0 = { nounwind readnone }
++attributes #1 = { nounwind }
++attributes #2 = { nounwind readonly }
++
++!llvm.module.flags = !{!0}
++!pauseresume = !{!1}
++!llvm.ident = !{!2}
++!dx.version = !{!3}
++!dx.valver = !{!4}
++!dx.shaderModel = !{!5}
++!dx.resources = !{!6}
++!dx.typeAnnotations = !{!9, !14}
++!dx.entryPoints = !{!21}
++
++!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 5}
++!4 = !{i32 1, i32 8}
++!5 = !{!"ps", i32 6, i32 5}
++!6 = !{null, null, !7, null}
++!7 = !{!8}
++!8 = !{i32 0, %cbuffer_g* @cbuffer_g, !"cbuffer_g", i32 0, i32 0, i32 1, i32 16, null}
++!9 = !{i32 0, %struct.return_val undef, !10, %cbuffer_g undef, !12}
++!10 = !{i32 16, !11}
++!11 = !{i32 6, !"value", i32 3, i32 0, i32 4, !"SV_Target0", i32 7, i32 9}
++!12 = !{i32 16, !13}
++!13 = !{i32 6, !"gu4", i32 3, i32 0, i32 7, i32 5}
++!14 = !{i32 1, void (<4 x float>*)* @main, !15}
++!15 = !{!16, !18}
++!16 = !{i32 0, !17, !17}
++!17 = !{}
++!18 = !{i32 1, !19, !20}
++!19 = !{i32 4, !"SV_Target0", i32 7, i32 9}
++!20 = !{i32 0}
++!21 = !{void (<4 x float>*)* @main, !"main", !22, !6, null}
++!22 = !{null, !23, null}
++!23 = !{!24}
++!24 = !{i32 0, !"SV_Target", i8 9, i8 16, !20, i8 0, i32 1, i8 4, i32 0, i8 0, null}
++!25 = !DILocation(line: 45, column: 25, scope: !26)
++!26 = !DISubprogram(name: "main", scope: !27, file: !27, line: 44, type: !28, isLocal: false, isDefinition: true, scopeLine: 44, flags: DIFlagPrototyped, isOptimized: false, function: void (<4 x float>*)* @main)
++!27 = !DIFile(filename: "/mnt/c/Users/amaiorano/Downloads/340196361/standalone_reduced.hlsl", directory: "")
++!28 = !DISubroutineType(types: !17)
++!29 = !DILocation(line: 10, column: 23, scope: !30, inlinedAt: !31)
++!30 = !DISubprogram(name: "f", scope: !27, file: !27, line: 5, type: !28, isLocal: false, isDefinition: true, scopeLine: 5, flags: DIFlagPrototyped, isOptimized: false)
++!31 = distinct !DILocation(line: 45, column: 25, scope: !26)
++!32 = !DILocation(line: 10, column: 15, scope: !30, inlinedAt: !31)
++!33 = !DILocation(line: 11, column: 18, scope: !30, inlinedAt: !31)
++!34 = !DILocation(line: 13, column: 11, scope: !30, inlinedAt: !31)
++!35 = !DILocation(line: 13, column: 9, scope: !30, inlinedAt: !31)
++!36 = !DILocation(line: 16, column: 17, scope: !30, inlinedAt: !31)
++!37 = !DILocation(line: 17, column: 9, scope: !30, inlinedAt: !31)
++!38 = !DILocation(line: 22, column: 9, scope: !30, inlinedAt: !31)
++!39 = !DILocation(line: 34, column: 12, scope: !30, inlinedAt: !31)
++!40 = !DILocation(line: 12, column: 17, scope: !30, inlinedAt: !31)
++!41 = !DILocation(line: 48, column: 10, scope: !26)
++!42 = !DILocation(line: 48, column: 3, scope: !26)

+ 2 - 1
patches/config.json

@@ -14,5 +14,6 @@
   { "patch_dir": "src/electron/patches/reclient-configs", "repo": "src/third_party/engflow-reclient-configs" },
   { "patch_dir": "src/electron/patches/angle", "repo": "src/third_party/angle" },
   { "patch_dir": "src/electron/patches/DirectXShaderCompiler", "repo": "src/third_party/dawn/third_party/dxc" },
-  { "patch_dir": "src/electron/patches/libaom", "repo": "src/third_party/libaom/source/libaom"}
+  { "patch_dir": "src/electron/patches/libaom", "repo": "src/third_party/libaom/source/libaom"},
+  { "patch_dir": "src/electron/patches/dawn", "repo": "src/third_party/dawn" }
 ]

+ 1 - 0
patches/dawn/.patches

@@ -0,0 +1 @@
+dawn_dxc_disable_dxc_pass_structurize-loop-exits-for-unroll.patch

+ 34 - 0
patches/dawn/dawn_dxc_disable_dxc_pass_structurize-loop-exits-for-unroll.patch

@@ -0,0 +1,34 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Antonio Maiorano <[email protected]>
+Date: Mon, 17 Jun 2024 18:33:47 +0000
+Subject: dawn/dxc: disable DXC pass 'structurize-loop-exits-for-unroll'
+
+Multiple security bugs have been reported related to this optimization pass, and after careful consideration, we have decided to disable it.
+
+Bug: chromium:333508731
+Bug: chromium:339171223
+Bug: chromium:339169163
+Bug: chromium:346595893
+Change-Id: I5c9d7180ed09e7417c120595937bcb1013b6ce66
+Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/184422
+Commit-Queue: Antonio Maiorano <[email protected]>
+Reviewed-by: Natalie Chouinard <[email protected]>
+Reviewed-by: Austin Eng <[email protected]>
+Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/194160
+Reviewed-by: dan sinclair <[email protected]>
+
+diff --git a/src/dawn/native/d3d/ShaderUtils.cpp b/src/dawn/native/d3d/ShaderUtils.cpp
+index c0aeea4d192c4498c0e802f4c693e82cab395715..bfc2f0c5ba189e0912310c50a48d5e2233956223 100644
+--- a/src/dawn/native/d3d/ShaderUtils.cpp
++++ b/src/dawn/native/d3d/ShaderUtils.cpp
+@@ -58,6 +58,10 @@ std::vector<const wchar_t*> GetDXCArguments(std::wstring_view entryPointNameW,
+     arguments.push_back(L"-E");
+     arguments.push_back(entryPointNameW.data());
+ 
++    // TODO(chromium:346595893): Disable buggy DXC pass
++    arguments.push_back(L"-opt-disable");
++    arguments.push_back(L"structurize-loop-exits-for-unroll");
++
+     uint32_t compileFlags = r.compileFlags;
+     if (compileFlags & D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY) {
+         arguments.push_back(L"/Gec");