From 3e839b6d308bd6f6dbbccf785eb77e0dfcf57531 Mon Sep 17 00:00:00 2001 From: Antonio Maiorano Date: Tue, 1 Apr 2025 11:52:16 -0400 Subject: [PATCH 1/2] Fix assert due to unreachable discard When emitting discard in an unreachable code context (e.g. after an infinite loop), DXC would assert (if asserts enabled), or trigger a UBSAN failure because the discard instruction would have no parent. When an infinite loop is emitted during CodeGen, the InsertPt is cleared, thus subsequent discard instructions would be created, but no parent set. We skip emitting discard in this case, which follows the same pattern as is done for EmitIfStmt, and EmitSwitchStmt. --- tools/clang/lib/CodeGen/CGStmt.cpp | 4 ++++ .../FinishCodeGen/unreachable-discard.hlsl | 23 +++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 tools/clang/test/DXC/FinishCodeGen/unreachable-discard.hlsl diff --git a/tools/clang/lib/CodeGen/CGStmt.cpp b/tools/clang/lib/CodeGen/CGStmt.cpp index 080d824022..340550dbdd 100644 --- a/tools/clang/lib/CodeGen/CGStmt.cpp +++ b/tools/clang/lib/CodeGen/CGStmt.cpp @@ -525,6 +525,10 @@ void CodeGenFunction::EmitGotoStmt(const GotoStmt &S) { // HLSL Change Begins. void CodeGenFunction::EmitDiscardStmt(const DiscardStmt &S) { + // Skip unreachable discard. + if (!HaveInsertPoint()) + return; + CGM.getHLSLRuntime().EmitHLSLDiscard(*this); } // HLSL Change Ends. diff --git a/tools/clang/test/DXC/FinishCodeGen/unreachable-discard.hlsl b/tools/clang/test/DXC/FinishCodeGen/unreachable-discard.hlsl new file mode 100644 index 0000000000..67153727a3 --- /dev/null +++ b/tools/clang/test/DXC/FinishCodeGen/unreachable-discard.hlsl @@ -0,0 +1,23 @@ +// RUN: %dxc /T ps_6_5 -fcgl %s | FileCheck %s + +// Compiling this HLSL would trigger an assertion: +// While deleting: void (i32, float)* %dx.hl.op..void (i32, float) +// Use still stuck around after Def is destroyed: call void @"dx.hl.op..void (i32, float)"(i32 120, float -1.000000e+00), !dbg <0x503000001cc8> +// Error: assert(use_empty() && "Uses remain when a value is destroyed!") +// File: /src/external/DirectXShaderCompiler/lib/IR/Value.cpp(83) +// +// Bug was fixed in CodeGenFunction::EmitDiscardStmt by skipping the emission of +// an unreachable discard. + +// CHECK: define void @main() +// CHECK: while.body: +// CHECK-NEXT: br label %while.body +// CHECK: return: +// CHECK-NEXT: ret void +// CHECK-NOT: call void @"dx.hl.op..void (i32, float)" + +void main() { + while (true) { + } + discard; +} From 6ff0fcad082c2db121f06172a72661d801e1d5b1 Mon Sep 17 00:00:00 2001 From: Antonio Maiorano Date: Tue, 1 Apr 2025 16:49:11 -0400 Subject: [PATCH 2/2] Fix test --- tools/clang/test/DXC/FinishCodeGen/unreachable-discard.hlsl | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tools/clang/test/DXC/FinishCodeGen/unreachable-discard.hlsl b/tools/clang/test/DXC/FinishCodeGen/unreachable-discard.hlsl index 67153727a3..77c0f51911 100644 --- a/tools/clang/test/DXC/FinishCodeGen/unreachable-discard.hlsl +++ b/tools/clang/test/DXC/FinishCodeGen/unreachable-discard.hlsl @@ -10,11 +10,9 @@ // an unreachable discard. // CHECK: define void @main() -// CHECK: while.body: -// CHECK-NEXT: br label %while.body -// CHECK: return: -// CHECK-NEXT: ret void +// CHECK: br label % // CHECK-NOT: call void @"dx.hl.op..void (i32, float)" +// CHECK: ret void void main() { while (true) {