chore: [29-x-y] cherry-pick 7 changes from 3-M125 (#42589)

This commit is contained in:
Pedro Pontes
2024-06-21 03:28:08 -07:00
committed by GitHub
parent 914d8f373e
commit fe869081b3
13 changed files with 1491 additions and 1 deletions

View File

@@ -3,3 +3,5 @@ cherry-pick-bc18aec94c82.patch
cherry-pick-bd7aa9779873.patch
cherry-pick-2a434fd0af6b.patch
cherry-pick-867c1001637e.patch
cherry-pick-0b785e88fefa.patch
cherry-pick-511cfef8e050.patch

View File

@@ -0,0 +1,523 @@
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)

View File

@@ -0,0 +1,243 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Antonio Maiorano <amaiorano@google.com>
Date: Mon, 27 May 2024 15:41:40 -0400
Subject: Fix use-after-free in SimplifyCFG (#6628)
When SimplifySwitchOnSelect calls SimplifyTerminatorOnSelect, it holds
onto the select's condition value to use for the conditional branch it
replaces the switch with. When removing the switch's unused
predecessors, it must make sure not to delete PHIs in case one of them
is used by the condition value, otherwise the condition value itself may
get deleted, resulting in an use-after-free.
Note that this was fixed in LLVM as well:
https://github.com/llvm/llvm-project/commit/dc3b67b4cad5c18a687edfabd50779c3c656c620
Bug: chromium:338103465
Change-Id: Iff5d5f2e3ecf38a3fb22bbc65e7c33ad0de659fb
Reviewed-on: https://chromium-review.googlesource.com/c/external/github.com/microsoft/DirectXShaderCompiler/+/5570018
Reviewed-by: James Price <jrprice@google.com>
Reviewed-by: Natalie Chouinard <chouinard@chromium.org>
diff --git a/lib/Transforms/Utils/SimplifyCFG.cpp b/lib/Transforms/Utils/SimplifyCFG.cpp
index b45caa2929a5cc3aa064fdbd9c06c20ad9e1e155..0d3ba1e00719060c1e71fa238726f0c63bd5b32f 100644
--- a/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -2619,7 +2619,10 @@ static bool SimplifyTerminatorOnSelect(TerminatorInst *OldTerm, Value *Cond,
else if (Succ == KeepEdge2)
KeepEdge2 = nullptr;
else
- Succ->removePredecessor(OldTerm->getParent());
+ Succ->removePredecessor(
+ OldTerm->getParent(),
+ /*DontDeleteUselessPHIs=*/true // HLSL Change: foward port LLVM fix
+ );
}
IRBuilder<> Builder(OldTerm);
diff --git a/tools/clang/test/DXC/Passes/SimplifyCFG/simplifycfg-uaf-select-condition.ll b/tools/clang/test/DXC/Passes/SimplifyCFG/simplifycfg-uaf-select-condition.ll
new file mode 100644
index 0000000000000000000000000000000000000000..149906c11285ed99a19c0fe1743801a795827792
--- /dev/null
+++ b/tools/clang/test/DXC/Passes/SimplifyCFG/simplifycfg-uaf-select-condition.ll
@@ -0,0 +1,199 @@
+; RUN: %dxopt %s -hlsl-passes-resume -simplifycfg -S | FileCheck %s
+
+; The IR below comes from the following HLSL.
+; Compiling this HLSL with dxc was resulting in an ASAN
+; use-after-free in SimplifyCFG during
+; SimplifyTerminatorOnSelect because it was deleting
+; a PHI node with an input value that the pass later
+; emits (the select condition value).
+
+; ByteAddressBuffer buff : register(t0);
+;
+; [numthreads(1, 1, 1)]
+; void main() {
+; if (buff.Load(0u)) {
+; return;
+; }
+;
+; int i = 0;
+; int j = 0;
+; while (true) {
+; bool a = (i < 2);
+; switch(i) {
+; case 0: {
+; while (true) {
+; bool b = (j < 2);
+; if (b) {
+; } else {
+; break;
+; }
+; while (true) {
+; int unused = 0;
+; while (true) {
+; if (a) break;
+; }
+; while (true) {
+; while (true) {
+; if (b) {
+; if (b) return;
+; } else {
+; break;
+; }
+; while (true) {
+; i = 0;
+; if (b) break;
+; }
+; if (a) break;
+; }
+; if (a) break;
+; }
+; if (a) break;
+; }
+; j = (j + 2);
+; }
+; }
+; }
+; }
+; }
+
+; Make sure the phi node did not get deleted by simplifycfg
+; CHECK: cleanup:
+; CHECK-NEXT: %cleanup.dest.slot.0 = phi i32 [ 1, %while.body.20 ], [ %.mux, %while.end.37 ]
+; CHECK-NEXT: switch i32 %cleanup.dest.slot.0, label %cleanup.46 [
+
+;
+; Buffer Definitions:
+;
+;
+; Resource Bindings:
+;
+; Name Type Format Dim ID HLSL Bind Count
+; ------------------------------ ---------- ------- ----------- ------- -------------- ------
+; 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 }
+
+@"\01?buff@@3UByteAddressBuffer@@A" = external global %struct.ByteAddressBuffer, align 4
+
+; Function Attrs: nounwind
+define void @main() #0 {
+entry:
+ %0 = load %struct.ByteAddressBuffer, %struct.ByteAddressBuffer* @"\01?buff@@3UByteAddressBuffer@@A", !dbg !17 ; line:5 col:7
+ %1 = call %dx.types.Handle @"dx.hl.createhandle..%dx.types.Handle (i32, %struct.ByteAddressBuffer)"(i32 0, %struct.ByteAddressBuffer %0), !dbg !17 ; line:5 col:7
+ %2 = call %dx.types.Handle @"dx.hl.annotatehandle..%dx.types.Handle (i32, %dx.types.Handle, %dx.types.ResourceProperties, %struct.ByteAddressBuffer)"(i32 14, %dx.types.Handle %1, %dx.types.ResourceProperties { i32 11, i32 0 }, %struct.ByteAddressBuffer undef), !dbg !17 ; line:5 col:7
+ %3 = call i32 @"dx.hl.op.ro.i32 (i32, %dx.types.Handle, i32)"(i32 231, %dx.types.Handle %2, i32 0), !dbg !17 ; line:5 col:7
+ %tobool = icmp ne i32 %3, 0, !dbg !17 ; line:5 col:7
+ br i1 %tobool, label %return, label %while.body, !dbg !17 ; line:5 col:7
+
+while.body: ; preds = %while.body.3, %while.body, %cleanup.46, %entry
+ %j.0 = phi i32 [ 0, %entry ], [ %j.1, %cleanup.46 ], [ %j.0, %while.body ], [ %j.1, %while.body.3 ]
+ %i.0 = phi i32 [ 0, %entry ], [ %i.1, %cleanup.46 ], [ %i.0, %while.body ], [ %i.1, %while.body.3 ]
+ %cmp = icmp slt i32 %i.0, 2, !dbg !21 ; line:12 col:17
+ %cond = icmp eq i32 %i.0, 0, !dbg !22 ; line:13 col:5
+ br i1 %cond, label %while.body.3, label %while.body, !dbg !22 ; line:13 col:5
+
+while.body.3: ; preds = %cleanup.46.thread, %while.body, %cleanup.46
+ %j.1 = phi i32 [ %j.1, %cleanup.46 ], [ %j.0, %while.body ], [ %add, %cleanup.46.thread ]
+ %i.1 = phi i32 [ %i.1, %cleanup.46 ], [ %i.0, %while.body ], [ %i.1, %cleanup.46.thread ]
+ %cmp4 = icmp slt i32 %j.1, 2, !dbg !23 ; line:16 col:23
+ br i1 %cmp4, label %while.body.11, label %while.body, !dbg !24 ; line:17 col:15
+
+while.body.11: ; preds = %while.body.3, %cleanup
+ br label %while.body.13, !dbg !25 ; line:23 col:13
+
+while.body.13: ; preds = %while.body.13, %while.body.11
+ br i1 %cmp, label %while.body.20, label %while.body.13, !dbg !26 ; line:24 col:19
+
+while.body.20: ; preds = %while.body.13, %while.end.37
+ br i1 %cmp4, label %cleanup, label %while.end.37, !dbg !27 ; line:28 col:21
+
+while.end.37: ; preds = %while.body.20
+ br i1 %cmp, label %cleanup, label %while.body.20, !dbg !28 ; line:39 col:19
+
+cleanup: ; preds = %while.end.37, %while.body.20
+ %cleanup.dest.slot.0 = phi i32 [ 1, %while.body.20 ], [ 8, %while.end.37 ]
+ switch i32 %cleanup.dest.slot.0, label %cleanup.46 [
+ i32 0, label %while.body.11
+ i32 8, label %cleanup.46.thread
+ ]
+
+cleanup.46.thread: ; preds = %cleanup
+ %add = add nsw i32 %j.1, 2, !dbg !29 ; line:43 col:18
+ br label %while.body.3
+
+cleanup.46: ; preds = %cleanup
+ switch i32 %cleanup.dest.slot.0, label %return [
+ i32 0, label %while.body.3
+ i32 6, label %while.body
+ ]
+
+return: ; preds = %cleanup.46, %entry
+ ret void, !dbg !30 ; line:48 col:1
+}
+
+; Function Attrs: nounwind
+declare void @llvm.lifetime.start(i64, i8* nocapture) #0
+
+; Function Attrs: nounwind
+declare void @llvm.lifetime.end(i64, i8* nocapture) #0
+
+; Function Attrs: nounwind readonly
+declare i32 @"dx.hl.op.ro.i32 (i32, %dx.types.Handle, i32)"(i32, %dx.types.Handle, i32) #1
+
+; Function Attrs: nounwind readnone
+declare %dx.types.Handle @"dx.hl.createhandle..%dx.types.Handle (i32, %struct.ByteAddressBuffer)"(i32, %struct.ByteAddressBuffer) #2
+
+; Function Attrs: nounwind readnone
+declare %dx.types.Handle @"dx.hl.annotatehandle..%dx.types.Handle (i32, %dx.types.Handle, %dx.types.ResourceProperties, %struct.ByteAddressBuffer)"(i32, %dx.types.Handle, %dx.types.ResourceProperties, %struct.ByteAddressBuffer) #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.typeAnnotations = !{!6}
+!dx.entryPoints = !{!10}
+!dx.fnprops = !{!14}
+!dx.options = !{!15, !16}
+
+!0 = !{i32 2, !"Debug Info Version", i32 3}
+!1 = !{!"hlsl-hlemit", !"hlsl-hlensure"}
+!2 = !{!"dxc(private) 1.8.0.4514 (d9bd2a706-dirty)"}
+!3 = !{i32 1, i32 6}
+!4 = !{i32 1, i32 8}
+!5 = !{!"cs", i32 6, i32 6}
+!6 = !{i32 1, void ()* @main, !7}
+!7 = !{!8}
+!8 = !{i32 1, !9, !9}
+!9 = !{}
+!10 = !{void ()* @main, !"main", null, !11, null}
+!11 = !{!12, null, null, null}
+!12 = !{!13}
+!13 = !{i32 0, %struct.ByteAddressBuffer* @"\01?buff@@3UByteAddressBuffer@@A", !"buff", i32 0, i32 0, i32 1, i32 11, i32 0, null}
+!14 = !{void ()* @main, i32 5, i32 1, i32 1, i32 1}
+!15 = !{i32 64}
+!16 = !{i32 -1}
+!17 = !DILocation(line: 5, column: 7, scope: !18)
+!18 = !DISubprogram(name: "main", scope: !19, file: !19, line: 4, type: !20, isLocal: false, isDefinition: true, scopeLine: 4, flags: DIFlagPrototyped, isOptimized: false, function: void ()* @main)
+!19 = !DIFile(filename: "/mnt/c/Users/amaiorano/Downloads/338103465/standalone_reduced.hlsl", directory: "")
+!20 = !DISubroutineType(types: !9)
+!21 = !DILocation(line: 12, column: 17, scope: !18)
+!22 = !DILocation(line: 13, column: 5, scope: !18)
+!23 = !DILocation(line: 16, column: 23, scope: !18)
+!24 = !DILocation(line: 17, column: 15, scope: !18)
+!25 = !DILocation(line: 23, column: 13, scope: !18)
+!26 = !DILocation(line: 24, column: 19, scope: !18)
+!27 = !DILocation(line: 28, column: 21, scope: !18)
+!28 = !DILocation(line: 39, column: 19, scope: !18)
+!29 = !DILocation(line: 43, column: 18, scope: !18)
+!30 = !DILocation(line: 48, column: 1, scope: !18)

View File

@@ -146,3 +146,5 @@ cherry-pick-03609e39be8c.patch
x11_use_localized_display_label_only_for_browser_process.patch
cherry-pick-b922fcb61e3b.patch
cherry-pick-0d9598145069.patch
cherry-pick-24329fe5c4d0.patch
m120-lts_mediasession_use_a_mediasessionimpl_weakptr_in.patch

View File

@@ -0,0 +1,106 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Nidhi Jaju <nidhijaju@chromium.org>
Date: Fri, 24 May 2024 01:26:02 +0000
Subject: Streams: Check if buffer is detached when filling pull-into
descriptor
The pull-into descriptor can become out-of-sync with the array buffer
when the buffer is detached. This CL adds a check to see if the buffer
is detached before trying to fill it.
(cherry picked from commit cd405492789ec4bc6ecd598754154c527ff60e95)
Bug: 339877167
Change-Id: Ibf46a75e36dc739910db07f2e88ff9998c21e8a8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5553232
Reviewed-by: Domenic Denicola <domenic@chromium.org>
Commit-Queue: Nidhi Jaju <nidhijaju@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#1303628}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5553411
Cr-Commit-Position: refs/branch-heads/6367@{#1228}
Cr-Branched-From: d158c6dc6e3604e6f899041972edf26087a49740-refs/heads/main@{#1274542}
diff --git a/third_party/blink/renderer/core/streams/readable_byte_stream_controller.cc b/third_party/blink/renderer/core/streams/readable_byte_stream_controller.cc
index 85e2214ca95790f547819e2a14628d342f7913bb..a844d84d20e68172e285cefe3301c49f3edfbd3a 100644
--- a/third_party/blink/renderer/core/streams/readable_byte_stream_controller.cc
+++ b/third_party/blink/renderer/core/streams/readable_byte_stream_controller.cc
@@ -494,7 +494,8 @@ void ReadableByteStreamController::ProcessPullIntoDescriptorsUsingQueue(
controller->pending_pull_intos_[0];
// c. If ! ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(
// controller, pullIntoDescriptor) is true,
- if (FillPullIntoDescriptorFromQueue(controller, pull_into_descriptor)) {
+ if (FillPullIntoDescriptorFromQueue(controller, pull_into_descriptor,
+ exception_state)) {
// i. Perform !
// ReadableByteStreamControllerShiftPendingPullInto(controller).
ShiftPendingPullInto(controller);
@@ -505,6 +506,15 @@ void ReadableByteStreamController::ProcessPullIntoDescriptorsUsingQueue(
pull_into_descriptor, exception_state);
DCHECK(!exception_state.HadException());
}
+ if (exception_state.HadException()) {
+ // Instead of returning a rejection, which is inconvenient here,
+ // call ControllerError(). The only difference this makes is that it
+ // happens synchronously, but that should not be observable.
+ ReadableByteStreamController::Error(script_state, controller,
+ exception_state.GetException());
+ exception_state.ClearException();
+ return;
+ }
}
}
@@ -989,7 +999,12 @@ void ReadableByteStreamController::FillHeadPullIntoDescriptor(
bool ReadableByteStreamController::FillPullIntoDescriptorFromQueue(
ReadableByteStreamController* controller,
- PullIntoDescriptor* pull_into_descriptor) {
+ PullIntoDescriptor* pull_into_descriptor,
+ ExceptionState& exception_state) {
+ if (pull_into_descriptor->buffer->IsDetached()) {
+ exception_state.ThrowTypeError("buffer is detached");
+ return false;
+ }
// https://streams.spec.whatwg.org/#readable-byte-stream-controller-fill-pull-into-descriptor-from-queue
// 1. Let elementSize be pullIntoDescriptor.[[elementSize]].
const size_t element_size = pull_into_descriptor->element_size;
@@ -1240,7 +1255,8 @@ void ReadableByteStreamController::PullInto(
// a. If !
// ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller,
// pullIntoDescriptor) is true,
- if (FillPullIntoDescriptorFromQueue(controller, pull_into_descriptor)) {
+ if (FillPullIntoDescriptorFromQueue(controller, pull_into_descriptor,
+ exception_state)) {
// i. Let filledView be !
// ReadableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescriptor).
DOMArrayBufferView* filled_view = ConvertPullIntoDescriptor(
@@ -1254,6 +1270,15 @@ void ReadableByteStreamController::PullInto(
// iv. Return.
return;
}
+ if (exception_state.HadException()) {
+ // Instead of returning a rejection, which is inconvenient here,
+ // call ControllerError(). The only difference this makes is that it
+ // happens synchronously, but that should not be observable.
+ ReadableByteStreamController::Error(script_state, controller,
+ exception_state.GetException());
+ exception_state.ClearException();
+ return;
+ }
// b. If controller.[[closeRequested]] is true,
if (controller->close_requested_) {
// i. Let e be a TypeError exception.
diff --git a/third_party/blink/renderer/core/streams/readable_byte_stream_controller.h b/third_party/blink/renderer/core/streams/readable_byte_stream_controller.h
index aff7d589cef5a32f43e1dc0b06aa0d2921e39169..f31f660fddbc01d95dff904ad9ac5b1cf3ee8d86 100644
--- a/third_party/blink/renderer/core/streams/readable_byte_stream_controller.h
+++ b/third_party/blink/renderer/core/streams/readable_byte_stream_controller.h
@@ -218,7 +218,8 @@ class CORE_EXPORT ReadableByteStreamController
// https://streams.spec.whatwg.org/#readable-byte-stream-controller-fill-pull-into-descriptor-from-queue
static bool FillPullIntoDescriptorFromQueue(ReadableByteStreamController*,
- PullIntoDescriptor*);
+ PullIntoDescriptor*,
+ ExceptionState&);
// https://streams.spec.whatwg.org/#abstract-opdef-readablebytestreamcontrollerfillreadrequestfromqueue
static void FillReadRequestFromQueue(ScriptState*,

View File

@@ -0,0 +1,207 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Zakhar Voit <voit@google.com>
Date: Fri, 7 Jun 2024 11:26:03 +0000
Subject: MediaSession: Use a MediaSessionImpl WeakPtr in
MediaSessionServiceImpl
Currently, every time MediaSessionServiceImpl wants to talk to its
associated MediaSessionImpl, it recalculates it from its
RenderFrameHostId. This can lead to issues where a
MediaSessionServiceImpl of a disconnected RenderFrameHost can no longer
access the MediaSessionImpl to tell it that it is being deleted,
leaving MediaSessionImpl with a dangling raw_ptr.
(cherry picked from commit 1f0de3303671c6c041930c7f4f8a9ad017a7f211)
(cherry picked from commit 11c5f7911caab6930812a515eac27e35776ba35c)
Bug: 338929744
Change-Id: I092d217d4a975b67a84280687ed5461a14ead98a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5577944
Commit-Queue: Tommy Steimel <steimel@chromium.org>
Cr-Original-Commit-Position: refs/branch-heads/6367@{#1245}
Cr-Original-Branched-From: d158c6dc6e3604e6f899041972edf26087a49740-refs/heads/main@{#1274542}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5583452
Owners-Override: Michael Ershov <miersh@google.com>
Commit-Queue: Michael Ershov <miersh@google.com>
Reviewed-by: Dale Curtis <dalecurtis@chromium.org>
Reviewed-by: Michael Ershov <miersh@google.com>
Cr-Commit-Position: refs/branch-heads/6099@{#2035}
Cr-Branched-From: e6ee4500f7d6549a9ac1354f8d056da49ef406be-refs/heads/main@{#1217362}
diff --git a/content/browser/media/session/media_session_impl.cc b/content/browser/media/session/media_session_impl.cc
index 5ccef5240eef2e3b5c82bc50b97331e1b2fb9f31..710aeb26aee5bcfd95fef96fc7b8be7aa27173ad 100644
--- a/content/browser/media/session/media_session_impl.cc
+++ b/content/browser/media/session/media_session_impl.cc
@@ -1669,6 +1669,10 @@ const base::UnguessableToken& MediaSessionImpl::GetRequestId() const {
return delegate_->request_id();
}
+base::WeakPtr<MediaSessionImpl> MediaSessionImpl::GetWeakPtr() {
+ return weak_factory_.GetWeakPtr();
+}
+
void MediaSessionImpl::RebuildAndNotifyActionsChanged() {
std::set<media_session::mojom::MediaSessionAction> actions =
routed_service_ ? routed_service_->actions()
diff --git a/content/browser/media/session/media_session_impl.h b/content/browser/media/session/media_session_impl.h
index 1f30f99fdd94617e3ddb8fb701c01201fbebf9df..af0f967b45e52778837ea716bc8290c6c0e20a6a 100644
--- a/content/browser/media/session/media_session_impl.h
+++ b/content/browser/media/session/media_session_impl.h
@@ -17,6 +17,7 @@
#include "base/containers/id_map.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/raw_ptr_exclusion.h"
+#include "base/memory/weak_ptr.h"
#include "base/timer/timer.h"
#include "build/build_config.h"
#include "content/browser/media/session/audio_focus_delegate.h"
@@ -346,6 +347,9 @@ class MediaSessionImpl : public MediaSession,
// Returns the Audio Focus request ID associated with this media session.
const base::UnguessableToken& GetRequestId() const;
+ // Returns a WeakPtr to `this`.
+ base::WeakPtr<MediaSessionImpl> GetWeakPtr();
+
CONTENT_EXPORT bool HasImageCacheForTest(const GURL& image_url) const;
// Make sure that all observers have received any pending callbacks from us,
@@ -641,6 +645,8 @@ class MediaSessionImpl : public MediaSession,
media_session::mojom::RemotePlaybackMetadataPtr remote_playback_metadata_;
+ base::WeakPtrFactory<MediaSessionImpl> weak_factory_{this};
+
WEB_CONTENTS_USER_DATA_KEY_DECL();
};
diff --git a/content/browser/media/session/media_session_service_impl.cc b/content/browser/media/session/media_session_service_impl.cc
index 532d1161b5321fbe37552f1caca2d20782356f36..a3ca009421a22d51a9d85f4665dd769319d26c22 100644
--- a/content/browser/media/session/media_session_service_impl.cc
+++ b/content/browser/media/session/media_session_service_impl.cc
@@ -22,14 +22,16 @@ MediaSessionServiceImpl::MediaSessionServiceImpl(
: render_frame_host_id_(render_frame_host->GetGlobalId()),
playback_state_(blink::mojom::MediaSessionPlaybackState::NONE) {
MediaSessionImpl* session = GetMediaSession();
- if (session)
- session->OnServiceCreated(this);
+ if (session) {
+ media_session_ = session->GetWeakPtr();
+ media_session_->OnServiceCreated(this);
+ }
}
MediaSessionServiceImpl::~MediaSessionServiceImpl() {
- MediaSessionImpl* session = GetMediaSession();
- if (session)
- session->OnServiceDestroyed(this);
+ if (media_session_) {
+ media_session_->OnServiceDestroyed(this);
+ }
}
// static
@@ -70,17 +72,17 @@ void MediaSessionServiceImpl::SetClient(
void MediaSessionServiceImpl::SetPlaybackState(
blink::mojom::MediaSessionPlaybackState state) {
playback_state_ = state;
- MediaSessionImpl* session = GetMediaSession();
- if (session)
- session->OnMediaSessionPlaybackStateChanged(this);
+ if (media_session_) {
+ media_session_->OnMediaSessionPlaybackStateChanged(this);
+ }
}
void MediaSessionServiceImpl::SetPositionState(
const std::optional<media_session::MediaPosition>& position) {
position_ = position;
- MediaSessionImpl* session = GetMediaSession();
- if (session)
- session->RebuildAndNotifyMediaPositionChanged();
+ if (media_session_) {
+ media_session_->RebuildAndNotifyMediaPositionChanged();
+ }
}
void MediaSessionServiceImpl::SetMetadata(
@@ -102,48 +104,48 @@ void MediaSessionServiceImpl::SetMetadata(
metadata_ = std::move(metadata);
}
- MediaSessionImpl* session = GetMediaSession();
- if (session)
- session->OnMediaSessionMetadataChanged(this);
+ if (media_session_) {
+ media_session_->OnMediaSessionMetadataChanged(this);
+ }
}
void MediaSessionServiceImpl::SetMicrophoneState(
media_session::mojom::MicrophoneState microphone_state) {
microphone_state_ = microphone_state;
- MediaSessionImpl* session = GetMediaSession();
- if (session)
- session->OnMediaSessionInfoChanged(this);
+ if (media_session_) {
+ media_session_->OnMediaSessionInfoChanged(this);
+ }
}
void MediaSessionServiceImpl::SetCameraState(
media_session::mojom::CameraState camera_state) {
camera_state_ = camera_state;
- MediaSessionImpl* session = GetMediaSession();
- if (session)
- session->OnMediaSessionInfoChanged(this);
+ if (media_session_) {
+ media_session_->OnMediaSessionInfoChanged(this);
+ }
}
void MediaSessionServiceImpl::EnableAction(
media_session::mojom::MediaSessionAction action) {
actions_.insert(action);
- MediaSessionImpl* session = GetMediaSession();
- if (session)
- session->OnMediaSessionActionsChanged(this);
+ if (media_session_) {
+ media_session_->OnMediaSessionActionsChanged(this);
+ }
}
void MediaSessionServiceImpl::DisableAction(
media_session::mojom::MediaSessionAction action) {
actions_.erase(action);
- MediaSessionImpl* session = GetMediaSession();
- if (session)
- session->OnMediaSessionActionsChanged(this);
+ if (media_session_) {
+ media_session_->OnMediaSessionActionsChanged(this);
+ }
}
void MediaSessionServiceImpl::ClearActions() {
actions_.clear();
- MediaSessionImpl* session = GetMediaSession();
- if (session)
- session->OnMediaSessionActionsChanged(this);
+ if (media_session_) {
+ media_session_->OnMediaSessionActionsChanged(this);
+ }
}
MediaSessionImpl* MediaSessionServiceImpl::GetMediaSession() {
diff --git a/content/browser/media/session/media_session_service_impl.h b/content/browser/media/session/media_session_service_impl.h
index 4eeffe2a8bbc532d15e5deb7bc77eebea41326cf..514c043648e70b3c29a57ddc5faabaf85e103491 100644
--- a/content/browser/media/session/media_session_service_impl.h
+++ b/content/browser/media/session/media_session_service_impl.h
@@ -85,6 +85,8 @@ class CONTENT_EXPORT MediaSessionServiceImpl
const GlobalRenderFrameHostId render_frame_host_id_;
+ base::WeakPtr<MediaSessionImpl> media_session_;
+
mojo::Remote<blink::mojom::MediaSessionClient> client_;
blink::mojom::MediaSessionPlaybackState playback_state_;
blink::mojom::SpecMediaMetadataPtr metadata_;

View File

@@ -13,5 +13,6 @@
{ "patch_dir": "src/electron/patches/webrtc", "repo": "src/third_party/webrtc" },
{ "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/DirectXShaderCompiler", "repo": "src/third_party/dawn/third_party/dxc" },
{ "patch_dir": "src/electron/patches/libaom", "repo": "src/third_party/libaom/source/libaom"}
]

2
patches/libaom/.patches Normal file
View File

@@ -0,0 +1,2 @@
update_codec_config_after_svc_scale_controls.patch
encode_api_test_add_repro_for_chromium_339877165.patch

View File

@@ -0,0 +1,162 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: James Zern <jzern@google.com>
Date: Thu, 16 May 2024 13:44:52 -0700
Subject: encode_api_test: add repro for chromium 339877165
BUG=chromium:339877165
Change-Id: I69dcc2cda098ec96a34e1e5f7ef557ee8caf5521
(cherry picked from commit 01467cdbd524900eed283660836179fd1b2cd536)
diff --git a/test/encode_api_test.cc b/test/encode_api_test.cc
index 605743f9be8ccc776aa3b8dcae0a79e7dc6711e6..c0a79fe734e7985b52bdbaaa5d8dec2c541275e5 100644
--- a/test/encode_api_test.cc
+++ b/test/encode_api_test.cc
@@ -556,6 +556,147 @@ TEST(EncodeAPI, Buganizer310457427) {
encoder.Encode(false);
}
+// Reproduces https://crbug.com/339877165.
+TEST(EncodeAPI, Buganizer339877165) {
+ // Initialize libaom encoder.
+ aom_codec_iface_t *const iface = aom_codec_av1_cx();
+ aom_codec_ctx_t enc;
+ aom_codec_enc_cfg_t cfg;
+
+ ASSERT_EQ(aom_codec_enc_config_default(iface, &cfg, AOM_USAGE_REALTIME),
+ AOM_CODEC_OK);
+
+ cfg.g_w = 2560;
+ cfg.g_h = 1600;
+ cfg.rc_target_bitrate = 231;
+ cfg.rc_end_usage = AOM_CBR;
+ cfg.g_threads = 8;
+
+ ASSERT_EQ(aom_codec_enc_init(&enc, iface, &cfg, 0), AOM_CODEC_OK);
+
+ // From libaom_av1_encoder.cc in WebRTC.
+ ASSERT_EQ(aom_codec_control(&enc, AOME_SET_CPUUSED, 11), AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_CDEF, 1), AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_TPL_MODEL, 0),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_DELTAQ_MODE, 0), AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_ORDER_HINT, 0),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_AQ_MODE, 3), AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AOME_SET_MAX_INTRA_BITRATE_PCT, 300),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_COEFF_COST_UPD_FREQ, 3),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_MODE_COST_UPD_FREQ, 3),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_MV_COST_UPD_FREQ, 3),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_TUNE_CONTENT, AOM_CONTENT_SCREEN),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_PALETTE, 1), AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_TILE_ROWS, 1), AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_TILE_COLUMNS, 2), AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_OBMC, 0), AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_NOISE_SENSITIVITY, 0),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_WARPED_MOTION, 0),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_GLOBAL_MOTION, 0),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_REF_FRAME_MVS, 0),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_SUPERBLOCK_SIZE,
+ AOM_SUPERBLOCK_SIZE_DYNAMIC),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_CFL_INTRA, 0),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_SMOOTH_INTRA, 0),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_ANGLE_DELTA, 0),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_FILTER_INTRA, 0),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_INTRA_DEFAULT_TX_ONLY, 1),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_DISABLE_TRELLIS_QUANT, 1),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_DIST_WTD_COMP, 0),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_DIFF_WTD_COMP, 0),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_DUAL_FILTER, 0),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_INTERINTRA_COMP, 0),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_INTERINTRA_WEDGE, 0),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_INTRA_EDGE_FILTER, 0),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_INTRABC, 0), AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_MASKED_COMP, 0),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_PAETH_INTRA, 0),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_QM, 0), AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_RECT_PARTITIONS, 0),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_RESTORATION, 0),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_SMOOTH_INTERINTRA, 0),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_TX64, 0), AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_MAX_REFERENCE_FRAMES, 3),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_enc_config_set(&enc, &cfg), AOM_CODEC_OK);
+
+ aom_svc_params_t svc_params = {};
+ svc_params.number_spatial_layers = 2;
+ svc_params.number_temporal_layers = 1;
+ svc_params.max_quantizers[0] = svc_params.max_quantizers[1] = 56;
+ svc_params.min_quantizers[0] = svc_params.min_quantizers[1] = 10;
+ svc_params.scaling_factor_num[0] = svc_params.scaling_factor_num[1] = 1;
+ svc_params.scaling_factor_den[0] = 2;
+ svc_params.scaling_factor_den[1] = 1;
+ svc_params.layer_target_bitrate[0] = cfg.rc_target_bitrate;
+ svc_params.framerate_factor[0] = 1;
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_SVC_PARAMS, &svc_params),
+ AOM_CODEC_OK);
+
+ aom_svc_layer_id_t layer_id = {};
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_SVC_LAYER_ID, &layer_id),
+ AOM_CODEC_OK);
+
+ aom_svc_ref_frame_config_t ref_frame_config = {};
+ ref_frame_config.refresh[0] = 1;
+ ASSERT_EQ(
+ aom_codec_control(&enc, AV1E_SET_SVC_REF_FRAME_CONFIG, &ref_frame_config),
+ AOM_CODEC_OK);
+
+ // Create input image.
+ aom_image_t *const image =
+ CreateGrayImage(AOM_IMG_FMT_I420, cfg.g_w, cfg.g_h);
+ ASSERT_NE(image, nullptr);
+
+ // Encode layer 0.
+ ASSERT_EQ(aom_codec_encode(&enc, image, 0, 1, 0), AOM_CODEC_OK);
+
+ layer_id.spatial_layer_id = 1;
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_SVC_LAYER_ID, &layer_id),
+ AOM_CODEC_OK);
+
+ ref_frame_config.refresh[0] = 0;
+ ASSERT_EQ(
+ aom_codec_control(&enc, AV1E_SET_SVC_REF_FRAME_CONFIG, &ref_frame_config),
+ AOM_CODEC_OK);
+
+ // Encode layer 1.
+ ASSERT_EQ(aom_codec_encode(&enc, image, 0, 1, 0), AOM_CODEC_OK);
+
+ // Free resources.
+ aom_img_free(image);
+ aom_codec_destroy(&enc);
+}
+
class EncodeAPIParameterized
: public testing::TestWithParam<std::tuple<
/*usage=*/unsigned int, /*speed=*/int, /*aq_mode=*/unsigned int>> {};

View File

@@ -0,0 +1,196 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: James Zern <jzern@google.com>
Date: Tue, 14 May 2024 17:54:10 -0700
Subject: update codec config after svc/scale controls
This ensures the encoder state/allocations stay in sync with scaling and
svc layer changes. In the SVC case, depending on the resolution,
differences in the chosen superblock size among layers may have caused a
crash. This was reproducible in WebRTC in screen content mode.
The fix is based on a change by Yuan Tong (tongyuan200097) [1]. It
refreshes the encoder config after AOME_SET_SCALEMODE,
AOME_SET_NUMBER_SPATIAL_LAYERS and AV1E_SET_SVC_PARAMS if no frames have
been encoded. AV1E_SET_SVC_PARAMS was missed in the original change.
[1]: https://aomedia-review.googlesource.com/c/aom/+/171941/2
Bug: chromium:339877165
Change-Id: Ib3d2a123b159898d7c7e19c81e89ff148920e1f1
(cherry picked from commit e42f4b1980bbbc772aa886d8b43a885461d7b89e)
diff --git a/av1/av1_cx_iface.c b/av1/av1_cx_iface.c
index 9214feb4e6f9dd068444e76bf8073a0bbe772134..68d6de21845a4e635f67f0a972126563d8f4fb7c 100644
--- a/av1/av1_cx_iface.c
+++ b/av1/av1_cx_iface.c
@@ -1602,37 +1602,42 @@ static aom_codec_err_t ctrl_get_baseline_gf_interval(aom_codec_alg_priv_t *ctx,
return AOM_CODEC_OK;
}
+static aom_codec_err_t update_encoder_cfg(aom_codec_alg_priv_t *ctx) {
+ set_encoder_config(&ctx->oxcf, &ctx->cfg, &ctx->extra_cfg);
+ av1_check_fpmt_config(ctx->ppi, &ctx->oxcf);
+ bool is_sb_size_changed = false;
+ av1_change_config_seq(ctx->ppi, &ctx->oxcf, &is_sb_size_changed);
+ for (int i = 0; i < ctx->ppi->num_fp_contexts; i++) {
+ AV1_COMP *const cpi = ctx->ppi->parallel_cpi[i];
+ struct aom_internal_error_info *const error = cpi->common.error;
+ if (setjmp(error->jmp)) {
+ error->setjmp = 0;
+ return error->error_code;
+ }
+ error->setjmp = 1;
+ av1_change_config(cpi, &ctx->oxcf, is_sb_size_changed);
+ error->setjmp = 0;
+ }
+ if (ctx->ppi->cpi_lap != NULL) {
+ AV1_COMP *const cpi_lap = ctx->ppi->cpi_lap;
+ struct aom_internal_error_info *const error = cpi_lap->common.error;
+ if (setjmp(error->jmp)) {
+ error->setjmp = 0;
+ return error->error_code;
+ }
+ error->setjmp = 1;
+ av1_change_config(cpi_lap, &ctx->oxcf, is_sb_size_changed);
+ error->setjmp = 0;
+ }
+ return AOM_CODEC_OK;
+}
+
static aom_codec_err_t update_extra_cfg(aom_codec_alg_priv_t *ctx,
const struct av1_extracfg *extra_cfg) {
const aom_codec_err_t res = validate_config(ctx, &ctx->cfg, extra_cfg);
if (res == AOM_CODEC_OK) {
ctx->extra_cfg = *extra_cfg;
- set_encoder_config(&ctx->oxcf, &ctx->cfg, &ctx->extra_cfg);
- av1_check_fpmt_config(ctx->ppi, &ctx->oxcf);
- bool is_sb_size_changed = false;
- av1_change_config_seq(ctx->ppi, &ctx->oxcf, &is_sb_size_changed);
- for (int i = 0; i < ctx->ppi->num_fp_contexts; i++) {
- AV1_COMP *const cpi = ctx->ppi->parallel_cpi[i];
- struct aom_internal_error_info *const error = cpi->common.error;
- if (setjmp(error->jmp)) {
- error->setjmp = 0;
- return error->error_code;
- }
- error->setjmp = 1;
- av1_change_config(cpi, &ctx->oxcf, is_sb_size_changed);
- error->setjmp = 0;
- }
- if (ctx->ppi->cpi_lap != NULL) {
- AV1_COMP *const cpi_lap = ctx->ppi->cpi_lap;
- struct aom_internal_error_info *const error = cpi_lap->common.error;
- if (setjmp(error->jmp)) {
- error->setjmp = 0;
- return error->error_code;
- }
- error->setjmp = 1;
- av1_change_config(cpi_lap, &ctx->oxcf, is_sb_size_changed);
- error->setjmp = 0;
- }
+ return update_encoder_cfg(ctx);
}
return res;
}
@@ -3573,11 +3578,23 @@ static aom_codec_err_t ctrl_set_scale_mode(aom_codec_alg_priv_t *ctx,
aom_scaling_mode_t *const mode = va_arg(args, aom_scaling_mode_t *);
if (mode) {
- const int res = av1_set_internal_size(
- &ctx->ppi->cpi->oxcf, &ctx->ppi->cpi->resize_pending_params,
- mode->h_scaling_mode, mode->v_scaling_mode);
- av1_check_fpmt_config(ctx->ppi, &ctx->ppi->cpi->oxcf);
- return (res == 0) ? AOM_CODEC_OK : AOM_CODEC_INVALID_PARAM;
+ AV1EncoderConfig *const oxcf =
+ ctx->ppi->seq_params_locked ? &ctx->ppi->cpi->oxcf : &ctx->oxcf;
+ const int res =
+ av1_set_internal_size(oxcf, &ctx->ppi->cpi->resize_pending_params,
+ mode->h_scaling_mode, mode->v_scaling_mode);
+ if (res == 0) {
+ // update_encoder_cfg() is somewhat costly and this control may be called
+ // multiple times, so update_encoder_cfg() is only called to ensure frame
+ // and superblock sizes are updated before they're fixed by the first
+ // encode call.
+ if (ctx->ppi->seq_params_locked) {
+ av1_check_fpmt_config(ctx->ppi, &ctx->ppi->cpi->oxcf);
+ return AOM_CODEC_OK;
+ }
+ return update_encoder_cfg(ctx);
+ }
+ return AOM_CODEC_INVALID_PARAM;
} else {
return AOM_CODEC_INVALID_PARAM;
}
@@ -3598,6 +3615,13 @@ static aom_codec_err_t ctrl_set_number_spatial_layers(aom_codec_alg_priv_t *ctx,
if (number_spatial_layers > MAX_NUM_SPATIAL_LAYERS)
return AOM_CODEC_INVALID_PARAM;
ctx->ppi->number_spatial_layers = number_spatial_layers;
+ // update_encoder_cfg() is somewhat costly and this control may be called
+ // multiple times, so update_encoder_cfg() is only called to ensure frame and
+ // superblock sizes are updated before they're fixed by the first encode
+ // call.
+ if (!ctx->ppi->seq_params_locked) {
+ return update_encoder_cfg(ctx);
+ }
return AOM_CODEC_OK;
}
@@ -3615,8 +3639,6 @@ static aom_codec_err_t ctrl_set_svc_params(aom_codec_alg_priv_t *ctx,
va_list args) {
AV1_PRIMARY *const ppi = ctx->ppi;
AV1_COMP *const cpi = ppi->cpi;
- AV1_COMMON *const cm = &cpi->common;
- AV1EncoderConfig *oxcf = &cpi->oxcf;
aom_svc_params_t *const params = va_arg(args, aom_svc_params_t *);
int64_t target_bandwidth = 0;
ppi->number_spatial_layers = params->number_spatial_layers;
@@ -3656,19 +3678,38 @@ static aom_codec_err_t ctrl_set_svc_params(aom_codec_alg_priv_t *ctx,
target_bandwidth += lc->layer_target_bitrate;
}
}
- if (cm->current_frame.frame_number == 0) {
- if (!cpi->ppi->seq_params_locked) {
- SequenceHeader *const seq_params = &ppi->seq_params;
- seq_params->operating_points_cnt_minus_1 =
- ppi->number_spatial_layers * ppi->number_temporal_layers - 1;
- av1_init_seq_coding_tools(ppi, &cpi->oxcf, 1);
- }
+
+ if (ppi->seq_params_locked) {
+ AV1EncoderConfig *const oxcf = &cpi->oxcf;
+ // Keep ctx->oxcf in sync in case further codec controls are made prior
+ // to encoding.
+ ctx->oxcf.rc_cfg.target_bandwidth = oxcf->rc_cfg.target_bandwidth =
+ target_bandwidth;
+ set_primary_rc_buffer_sizes(oxcf, ppi);
+ av1_update_layer_context_change_config(cpi, target_bandwidth);
+ check_reset_rc_flag(cpi);
+ } else {
+ // Note av1_init_layer_context() relies on cpi->oxcf. The order of that
+ // call and the ones in the other half of this block (which
+ // update_encoder_cfg() transitively makes) is important. So we keep
+ // ctx->oxcf and cpi->oxcf in sync here as update_encoder_cfg() will
+ // overwrite cpi->oxcf with ctx->oxcf.
+ ctx->oxcf.rc_cfg.target_bandwidth = cpi->oxcf.rc_cfg.target_bandwidth =
+ target_bandwidth;
+ SequenceHeader *const seq_params = &ppi->seq_params;
+ seq_params->operating_points_cnt_minus_1 =
+ ppi->number_spatial_layers * ppi->number_temporal_layers - 1;
+
av1_init_layer_context(cpi);
+ // update_encoder_cfg() is somewhat costly and this control may be called
+ // multiple times, so update_encoder_cfg() is only called to ensure frame
+ // and superblock sizes are updated before they're fixed by the first
+ // encode call.
+ return update_encoder_cfg(ctx);
}
- oxcf->rc_cfg.target_bandwidth = target_bandwidth;
- set_primary_rc_buffer_sizes(oxcf, cpi->ppi);
- av1_update_layer_context_change_config(cpi, target_bandwidth);
- check_reset_rc_flag(cpi);
+ } else if (!ppi->seq_params_locked) {
+ // Ensure frame and superblock sizes are updated.
+ return update_encoder_cfg(ctx);
}
av1_check_fpmt_config(ctx->ppi, &ctx->ppi->cpi->oxcf);
return AOM_CODEC_OK;

View File

@@ -6,3 +6,4 @@ cherry-pick-b3c01ac1e60a.patch
cherry-pick-6503a987d966.patch
cherry-pick-3e037e195e50.patch
cherry-pick-e7b64c6ee185.patch
cherry-pick-f911ff372723.patch

View File

@@ -0,0 +1,45 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shu-yu Guo <syg@chromium.org>
Date: Fri, 10 May 2024 12:08:04 -0700
Subject: Merged: [ic] Use slow stub element handler for non-JSObjects
Fixed: 339736513
(cherry picked from commit 8a69c7880844ab00ee2f32079579a040a87eedca)
Change-Id: If87462eb044c194798a32cb25a5f3648ff823196
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5555847
Commit-Queue: Shu-yu Guo <syg@chromium.org>
Reviewed-by: Adam Klein <adamk@chromium.org>
Commit-Queue: Adam Klein <adamk@chromium.org>
Auto-Submit: Shu-yu Guo <syg@chromium.org>
Cr-Commit-Position: refs/branch-heads/12.4@{#36}
Cr-Branched-From: 309640da62fae0485c7e4f64829627c92d53b35d-refs/heads/12.4.254@{#1}
Cr-Branched-From: 5dc24701432278556a9829d27c532f974643e6df-refs/heads/main@{#92862}
diff --git a/src/ic/ic.cc b/src/ic/ic.cc
index 61bb82aff98e4273b651801b875416c686de872e..34cf7eb6d2f5ef74b37103a6ee2356b8825d3f58 100644
--- a/src/ic/ic.cc
+++ b/src/ic/ic.cc
@@ -2349,15 +2349,16 @@ Handle<Object> KeyedStoreIC::StoreElementHandler(
isolate()),
IsStoreInArrayLiteralIC());
- if (IsJSProxyMap(*receiver_map)) {
+ if (!IsJSObjectMap(*receiver_map)) {
// DefineKeyedOwnIC, which is used to define computed fields in instances,
- // should be handled by the slow stub.
- if (IsDefineKeyedOwnIC()) {
- TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_SlowStub);
- return StoreHandler::StoreSlow(isolate(), store_mode);
+ // should handled by the slow stub below instead of the proxy stub.
+ if (IsJSProxyMap(*receiver_map) && !IsDefineKeyedOwnIC()) {
+ return StoreHandler::StoreProxy(isolate());
}
- return StoreHandler::StoreProxy(isolate());
+ // Wasm objects or other kind of special objects go through the slow stub.
+ TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_SlowStub);
+ return StoreHandler::StoreSlow(isolate(), store_mode);
}
// TODO(ishell): move to StoreHandler::StoreElement().