]> granicus.if.org Git - llvm/commitdiff
[ScheduleDAG] Make sure to process all def operands before any use operands
authorKrzysztof Parzyszek <kparzysz@codeaurora.org>
Tue, 10 May 2016 16:50:30 +0000 (16:50 +0000)
committerKrzysztof Parzyszek <kparzysz@codeaurora.org>
Tue, 10 May 2016 16:50:30 +0000 (16:50 +0000)
An example from Hexagon where things went wrong:
  %R0<def> = L2_loadrigp <ga:@fp04>      ; load function address
  J2_callr %R0<kill>, ..., %R0<imp-def>  ; call *R0, return value in R0

ScheduleDAGInstrs::buildSchedGraph would visit all instructions going
backwards, and in each instruction it would visit all operands in their
order on the operand list. In the case of this call, it visited the use
of R0 first, then removed it from the set Uses after it visited the def.
This caused the DAG to be missing the data dependence edge on R0 between
the load and the call.

Differential Revision: http://reviews.llvm.org/D20102

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

lib/CodeGen/ScheduleDAGInstrs.cpp
test/CodeGen/Hexagon/callr-dep-edge.ll [new file with mode: 0644]

index 34cebaed240b5c01c90db730b5a49ab53b6bb8e5..282019f3037235adba62b1b64e031ef968347ec1 100644 (file)
@@ -948,24 +948,41 @@ void ScheduleDAGInstrs::buildSchedGraph(AliasAnalysis *AA,
         "Cannot schedule terminators or labels!");
 
     // Add register-based dependencies (data, anti, and output).
+    // For some instructions (calls, returns, inline-asm, etc.) there can
+    // be explicit uses and implicit defs, in which case the use will appear
+    // on the operand list before the def. Do two passes over the operand
+    // list to make sure that defs are processed before any uses.
     bool HasVRegDef = false;
     for (unsigned j = 0, n = MI->getNumOperands(); j != n; ++j) {
       const MachineOperand &MO = MI->getOperand(j);
-      if (!MO.isReg()) continue;
+      if (!MO.isReg() || !MO.isDef())
+        continue;
       unsigned Reg = MO.getReg();
-      if (Reg == 0) continue;
+      if (Reg == 0)
+        continue;
 
       if (TRI->isPhysicalRegister(Reg))
         addPhysRegDeps(SU, j);
       else {
-        if (MO.isDef()) {
-          HasVRegDef = true;
-          addVRegDefDeps(SU, j);
-        }
-        else if (MO.readsReg()) // ignore undef operands
-          addVRegUseDeps(SU, j);
+        HasVRegDef = true;
+        addVRegDefDeps(SU, j);
       }
     }
+    // Now process all uses.
+    for (unsigned j = 0, n = MI->getNumOperands(); j != n; ++j) {
+      const MachineOperand &MO = MI->getOperand(j);
+      if (!MO.isReg() || !MO.isUse())
+        continue;
+      unsigned Reg = MO.getReg();
+      if (Reg == 0)
+        continue;
+
+      if (TRI->isPhysicalRegister(Reg))
+        addPhysRegDeps(SU, j);
+      else if (MO.readsReg()) // ignore undef operands
+        addVRegUseDeps(SU, j);
+    }
+
     // If we haven't seen any uses in this scheduling region, create a
     // dependence edge to ExitSU to model the live-out latency. This is required
     // for vreg defs with no in-region use, and prefetches with no vreg def.
diff --git a/test/CodeGen/Hexagon/callr-dep-edge.ll b/test/CodeGen/Hexagon/callr-dep-edge.ll
new file mode 100644 (file)
index 0000000..d2c6ae4
--- /dev/null
@@ -0,0 +1,20 @@
+; RUN: llc -march=hexagon < %s | FileCheck %s
+; Check that the callr and the load into r0 are not packetized together.
+
+target triple = "hexagon"
+
+@fp = common global i32 (...)* null, align 4
+
+; CHECK: r0 = memw
+; CHECK: {
+; CHECK: callr r0
+
+; Function Attrs: nounwind
+define i32 @foo() #0 {
+entry:
+  %0 = load i32 ()*, i32 ()** bitcast (i32 (...)** @fp to i32 ()**), align 4
+  %call = tail call i32 %0() #0
+  ret i32 %call
+}
+
+attributes #0 = { nounwind }