]> granicus.if.org Git - llvm/commitdiff
[ScheduleDAGRRList] Do not preschedule the node has ADJCALLSTACKDOWN parent
authorShiva Chen <shiva0217@gmail.com>
Fri, 18 Jan 2019 08:36:06 +0000 (08:36 +0000)
committerShiva Chen <shiva0217@gmail.com>
Fri, 18 Jan 2019 08:36:06 +0000 (08:36 +0000)
We should not pre-scheduled the node has ADJCALLSTACKDOWN parent,
or else, when bottom-up scheduling, ADJCALLSTACKDOWN and
ADJCALLSTACKUP may hold CallResource too long and make other
calls can't be scheduled. If there's no other available node
to schedule, the scheduler will try to rename the register by
creating copy to avoid the conflict which will fail because
CallResource is not a real physical register.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@351527 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/SelectionDAG/ScheduleDAGRRList.cpp
test/CodeGen/AVR/pre-schedule.ll [new file with mode: 0644]

index 8d75b8133a30263638f5c1fa40e4ddda5267b1f1..5bb9add43c4de9d48314d68b4e153911b4036d9a 100644 (file)
@@ -2939,6 +2939,29 @@ void RegReductionPQBase::PrescheduleNodesWithMultipleUses() {
             (cast<RegisterSDNode>(N->getOperand(1))->getReg()))
         continue;
 
+    SDNode *PredFrameSetup = nullptr;
+    for (const SDep &Pred : SU.Preds)
+      if (Pred.isCtrl() && Pred.getSUnit()) {
+        // Find the predecessor which is not data dependence.
+        SDNode *PredND = Pred.getSUnit()->getNode();
+
+        // If PredND is FrameSetup, we should not pre-scheduled the node,
+        // or else, when bottom up scheduling, ADJCALLSTACKDOWN and
+        // ADJCALLSTACKUP may hold CallResource too long and make other
+        // calls can't be scheduled. If there's no other available node
+        // to schedule, the schedular will try to rename the register by
+        // creating copy to avoid the conflict which will fail because
+        // CallResource is not a real physical register.
+        if (PredND && PredND->isMachineOpcode() &&
+            (PredND->getMachineOpcode() == TII->getCallFrameSetupOpcode())) {
+          PredFrameSetup = PredND;
+          break;
+        }
+      }
+    // Skip the node has FrameSetup parent.
+    if (PredFrameSetup != nullptr)
+      continue;
+
     // Locate the single data predecessor.
     SUnit *PredSU = nullptr;
     for (const SDep &Pred : SU.Preds)
diff --git a/test/CodeGen/AVR/pre-schedule.ll b/test/CodeGen/AVR/pre-schedule.ll
new file mode 100644 (file)
index 0000000..c724eea
--- /dev/null
@@ -0,0 +1,32 @@
+; RUN: llc < %s -march=avr | FileCheck %s
+target triple = "avr-unknown-unknown"
+
+; The case illustrate DAG schedular may pre-schedule the node has
+; ADJCALLSTACKDOWN parent, so ADJCALLSTACKUP may hold CallResource too long
+; and make other calls can't be scheduled. If there's no other available node
+; to schedule, the scheduler will try to rename the register by creating the
+; copy to avoid the conflict which will fail because CallResource is not a real
+; physical register.
+;
+; The issue is found by Tim on https://github.com/avr-rust/rust/issues/111 and
+; discuss in http://lists.llvm.org/pipermail/llvm-dev/2018-October/127083.html.
+
+define void @"main"() addrspace(1) {
+start:
+  %0 = or i64 undef, undef
+   br i1 undef, label %mul_and_call, label %fail
+
+  mul_and_call:
+  %1 = mul i64 %0, %0
+  call addrspace(1) void @"three_ints"(i64 undef, i64 %1, i64 %0)
+; The CHECK line only want to make sure the following assertion message
+; won't trigger due to create copy of artificial CallResource register.
+; llc: llvm/lib/CodeGen/TargetRegisterInfo.cpp:203: const llvm::TargetRegisterClass* llvm::TargetRegisterInfo::getMinimalPhysRegClass(unsigned int, llvm::MVT) const: Assertion `BestRC && "Couldn't find the register class"' failed.
+; CHECK: call    __muldi3
+  ret void
+
+  fail:
+    ret void
+}
+
+declare void @"three_ints"(i64, i64, i64) addrspace(1)