[ScheduleDAGFast] Fix crash due to incorrect live reg delay in fast scheduler - #200567
[ScheduleDAGFast] Fix crash due to incorrect live reg delay in fast scheduler#200567TianYe717 wants to merge 2 commits into
Conversation
|
@llvm/pr-subscribers-llvm-selectiondag @llvm/pr-subscribers-backend-x86 Author: Ye Tian (TianYe717) ChangesFixes #130730 When using DelayForLiveRegsBottomUp incorrectly delays SBB32ri because its predecessor BT32ri8 also touches EFLAGS, but SBB32ri itself is the live EFLAGS definition — it should never have been delayed. This triggers backtracking which inserts PHYS REG COPY nodes. The newly added artificial edges create a dependency cycle between SBB32ri and the copies, leaving no available nodes in the ready queue. The scheduler exits the main loop prematurely, and verification finds unscheduled nodes, which causes crash. For this case: Before: After: Test: Full diff: https://github.com/llvm/llvm-project/pull/200567.diff 2 Files Affected:
diff --git a/llvm/lib/CodeGen/SelectionDAG/ScheduleDAGFast.cpp b/llvm/lib/CodeGen/SelectionDAG/ScheduleDAGFast.cpp
index 9b76ebdb0f8fa..9b9a6798b013b 100644
--- a/llvm/lib/CodeGen/SelectionDAG/ScheduleDAGFast.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/ScheduleDAGFast.cpp
@@ -471,6 +471,8 @@ bool ScheduleDAGFast::DelayForLiveRegsBottomUp(SUnit *SU,
// If this node would clobber any "live" register, then it's not ready.
for (SDep &Pred : SU->Preds) {
if (Pred.isAssignedRegDep()) {
+ if (LiveRegDefs[Pred.getReg()] == SU)
+ continue;
CheckForLiveRegDef(Pred.getSUnit(), Pred.getReg(), LiveRegDefs,
RegAdded, LRegs, TRI);
}
diff --git a/llvm/test/CodeGen/X86/fast-sched-eflags-live-def.ll b/llvm/test/CodeGen/X86/fast-sched-eflags-live-def.ll
new file mode 100644
index 0000000000000..b5dfe6476e5b0
--- /dev/null
+++ b/llvm/test/CodeGen/X86/fast-sched-eflags-live-def.ll
@@ -0,0 +1,22 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc -mtriple=x86_64-unknown-linux-gnu -verify-machineinstrs -pre-RA-sched=fast -O3 %s -o - | FileCheck %s
+
+; Test that the fast scheduler correctly handles the case where a node being
+; scheduled is itself the live physical register definition (EFLAGS). Previously,
+; DelayForLiveRegsBottomUp would incorrectly delay such a node, leading to an
+; infinite loop of register copy insertion and a scheduling failure assertion.
+
+define i1 @Perl_pp_match(i32 %0) {
+; CHECK-LABEL: Perl_pp_match:
+; CHECK: .cfi_startproc
+; CHECK-NEXT: # %bb.0:
+; CHECK-NEXT: btl $1, %edi
+; CHECK-NEXT: sbbl $0, %edi
+; CHECK-NEXT: sete %al
+; CHECK-NEXT: retq
+entry:
+ %and176 = lshr i32 %0, 1
+ %and176.lobit = and i32 %and176, 1
+ %cmp179 = icmp eq i32 %0, %and176.lobit
+ ret i1 %cmp179
+}
|
|
Ping |
| // If this node would clobber any "live" register, then it's not ready. | ||
| for (SDep &Pred : SU->Preds) { | ||
| if (Pred.isAssignedRegDep()) { | ||
| if (LiveRegDefs[Pred.getReg()] == SU) |
fc56690 to
84a2639
Compare
Fixes #130730
When using
-pre-RA-sched=fast, the scheduler could crash with an assertion "!AnyNotSched" when scheduling a chain of instructions that produce and consume EFLAGS `DelayForLiveRegsBottomUp incorrectly delays SBB32ri because its predecessor BT32ri8 also touches EFLAGS, but SBB32ri itself is the live EFLAGS definition — it should never have been delayed. This triggers backtracking which inserts PHYS REG COPY nodes. The newly added artificial edges create a dependency cycle between SBB32ri and the copies, leaving no available nodes in the ready queue. The scheduler exits the main loop prematurely, and verification finds unscheduled nodes, which causes crash.
For this case:
Before:
After:
This result is the same as that of linearize and list-hybrid.
Test:
Added llvm/test/CodeGen/X86/fast-sched-eflags-live-def.ll which reproduces the crash with -verify-machineinstrs -pre-RA-sched=fast.