[llvm-commits] [llvm] r63370 - in /llvm/trunk: include/llvm/Analysis/AliasAnalysis.h lib/Analysis/BasicAliasAnalysis.cpp lib/CodeGen/ScheduleDAGInstrs.cpp

Dan Gohman gohman at apple.com
Thu Jan 29 18:49:14 PST 2009


Author: djg
Date: Thu Jan 29 20:49:14 2009
New Revision: 63370

URL: http://llvm.org/viewvc/llvm-project?rev=63370&view=rev
Log:
Fix a post-RA scheduling dependency bug.

If a MachineInstr doesn't have a memoperand but has an opcode that
is known to load or store, assume its memory reference may alias
*anything*, including stack slots which the compiler completely
controls.

To partially compensate for this, teach the ScheduleDAG building
code to do basic getUnderlyingValue analysis. This greatly
reduces the number of instructions that require restrictive
dependencies. This code will need to be revisited when we start
doing real alias analysis, but it should suffice for now.

Modified:
    llvm/trunk/include/llvm/Analysis/AliasAnalysis.h
    llvm/trunk/lib/Analysis/BasicAliasAnalysis.cpp
    llvm/trunk/lib/CodeGen/ScheduleDAGInstrs.cpp

Modified: llvm/trunk/include/llvm/Analysis/AliasAnalysis.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/AliasAnalysis.h?rev=63370&r1=63369&r2=63370&view=diff

==============================================================================
--- llvm/trunk/include/llvm/Analysis/AliasAnalysis.h (original)
+++ llvm/trunk/include/llvm/Analysis/AliasAnalysis.h Thu Jan 29 20:49:14 2009
@@ -345,6 +345,11 @@
   }
 };
 
+/// isIdentifiedObject - Return true if this pointer refers to a distinct and
+/// identifiable object.
+///
+bool isIdentifiedObject(const Value *V);
+
 } // End llvm namespace
 
 // Because of the way .a files work, we must force the BasicAA implementation to

Modified: llvm/trunk/lib/Analysis/BasicAliasAnalysis.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/BasicAliasAnalysis.cpp?rev=63370&r1=63369&r2=63370&view=diff

==============================================================================
--- llvm/trunk/lib/Analysis/BasicAliasAnalysis.cpp (original)
+++ llvm/trunk/lib/Analysis/BasicAliasAnalysis.cpp Thu Jan 29 20:49:14 2009
@@ -80,7 +80,7 @@
 ///    ByVal and NoAlias Arguments
 ///    NoAlias returns
 ///
-static bool isIdentifiedObject(const Value *V) {
+bool llvm::isIdentifiedObject(const Value *V) {
   if (isa<GlobalValue>(V) || isa<AllocationInst>(V) || isNoAliasCall(V))
     return true;
   if (const Argument *A = dyn_cast<Argument>(V))

Modified: llvm/trunk/lib/CodeGen/ScheduleDAGInstrs.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/ScheduleDAGInstrs.cpp?rev=63370&r1=63369&r2=63370&view=diff

==============================================================================
--- llvm/trunk/lib/CodeGen/ScheduleDAGInstrs.cpp (original)
+++ llvm/trunk/lib/CodeGen/ScheduleDAGInstrs.cpp Thu Jan 29 20:49:14 2009
@@ -13,6 +13,7 @@
 //===----------------------------------------------------------------------===//
 
 #define DEBUG_TYPE "sched-instrs"
+#include "llvm/Analysis/AliasAnalysis.h"
 #include "llvm/CodeGen/MachineDominators.h"
 #include "llvm/CodeGen/MachineFunctionPass.h"
 #include "llvm/CodeGen/MachineLoopInfo.h"
@@ -95,6 +96,82 @@
                                      const MachineDominatorTree &mdt)
   : ScheduleDAG(mf), MLI(mli), MDT(mdt) {}
 
+/// getOpcode - If this is an Instruction or a ConstantExpr, return the
+/// opcode value. Otherwise return UserOp1.
+static unsigned getOpcode(const Value *V) {
+  if (const Instruction *I = dyn_cast<Instruction>(V))
+    return I->getOpcode();
+  if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(V))
+    return CE->getOpcode();
+  // Use UserOp1 to mean there's no opcode.
+  return Instruction::UserOp1;
+}
+
+/// getUnderlyingObjectFromInt - This is the function that does the work of
+/// looking through basic ptrtoint+arithmetic+inttoptr sequences.
+static const Value *getUnderlyingObjectFromInt(const Value *V) {
+  do {
+    if (const User *U = dyn_cast<User>(V)) {
+      // If we find a ptrtoint, we can transfer control back to the
+      // regular getUnderlyingObjectFromInt.
+      if (getOpcode(U) == Instruction::PtrToInt)
+        return U->getOperand(0);
+      // If we find an add of a constant or a multiplied value, it's
+      // likely that the other operand will lead us to the base
+      // object. We don't have to worry about the case where the
+      // object address is somehow being computed bt the multiply,
+      // because our callers only care when the result is an
+      // identifibale object.
+      if (getOpcode(U) != Instruction::Add ||
+          (!isa<ConstantInt>(U->getOperand(1)) &&
+           getOpcode(U->getOperand(1)) != Instruction::Mul))
+        return V;
+      V = U->getOperand(0);
+    } else {
+      return V;
+    }
+    assert(isa<IntegerType>(V->getType()) && "Unexpected operand type!");
+  } while (1);
+}
+
+/// getUnderlyingObject - This is a wrapper around Value::getUnderlyingObject
+/// and adds support for basic ptrtoint+arithmetic+inttoptr sequences.
+static const Value *getUnderlyingObject(const Value *V) {
+  // First just call Value::getUnderlyingObject to let it do what it does.
+  do {
+    V = V->getUnderlyingObject();
+    // If it found an inttoptr, use special code to continue climing.
+    if (getOpcode(V) != Instruction::IntToPtr)
+      break;
+    const Value *O = getUnderlyingObjectFromInt(cast<User>(V)->getOperand(0));
+    // If that succeeded in finding a pointer, continue the search.
+    if (!isa<PointerType>(O->getType()))
+      break;
+    V = O;
+  } while (1);
+  return V;
+}
+
+/// getUnderlyingObjectForInstr - If this machine instr has memory reference
+/// information and it can be tracked to a normal reference to a known
+/// object, return the Value for that object. Otherwise return null.
+static const Value *getUnderlyingObjectForInstr(const MachineInstr *MI) {
+  if (!MI->hasOneMemOperand() ||
+      !MI->memoperands_begin()->getValue() ||
+      MI->memoperands_begin()->isVolatile())
+    return 0;
+
+  const Value *V = MI->memoperands_begin()->getValue();
+  if (!V)
+    return 0;
+
+  V = getUnderlyingObject(V);
+  if (!isa<PseudoSourceValue>(V) && !isIdentifiedObject(V))
+    return 0;
+
+  return V;
+}
+
 void ScheduleDAGInstrs::BuildSchedGraph() {
   SUnits.reserve(BB->size());
 
@@ -313,12 +390,8 @@
         // Unknown memory accesses. Assume the worst.
         ChainMMO = 0;
     } else if (TID.mayStore()) {
-      if (MI->hasOneMemOperand() &&
-          MI->memoperands_begin()->getValue() &&
-          !MI->memoperands_begin()->isVolatile() &&
-          isa<PseudoSourceValue>(MI->memoperands_begin()->getValue())) {
+      if (const Value *V = getUnderlyingObjectForInstr(MI)) {
         // A store to a specific PseudoSourceValue. Add precise dependencies.
-        const Value *V = MI->memoperands_begin()->getValue();
         // Handle the def in MemDefs, if there is one.
         std::map<const Value *, SUnit *>::iterator I = MemDefs.find(V);
         if (I != MemDefs.end()) {
@@ -337,6 +410,10 @@
                                        /*isNormalMemory=*/true));
           J->second.clear();
         }
+        // Add dependencies from all the PendingLoads, since without
+        // memoperands we must assume they alias anything.
+        for (unsigned k = 0, m = PendingLoads.size(); k != m; ++k)
+          PendingLoads[k]->addPred(SDep(SU, SDep::Order, SU->Latency));
         // Add a general dependence too, if needed.
         if (Chain)
           Chain->addPred(SDep(SU, SDep::Order, SU->Latency));
@@ -346,12 +423,8 @@
     } else if (TID.mayLoad()) {
       if (TII->isInvariantLoad(MI)) {
         // Invariant load, no chain dependencies needed!
-      } else if (MI->hasOneMemOperand() &&
-                 MI->memoperands_begin()->getValue() &&
-                 !MI->memoperands_begin()->isVolatile() &&
-                 isa<PseudoSourceValue>(MI->memoperands_begin()->getValue())) {
+      } else if (const Value *V = getUnderlyingObjectForInstr(MI)) {
         // A load from a specific PseudoSourceValue. Add precise dependencies.
-        const Value *V = MI->memoperands_begin()->getValue();
         std::map<const Value *, SUnit *>::iterator I = MemDefs.find(V);
         if (I != MemDefs.end())
           I->second->addPred(SDep(SU, SDep::Order, SU->Latency, /*Reg=*/0,
@@ -367,9 +440,15 @@
         // cases where memoperand information is unavailable.
         goto new_chain;
       } else {
-        // A normal load. Just depend on the general chain.
+        // A normal load. Depend on the general chain, as well as on
+        // all stores. In the absense of MachineMemOperand information,
+        // we can't even assume that the load doesn't alias well-behaved
+        // memory locations.
         if (Chain)
           Chain->addPred(SDep(SU, SDep::Order, SU->Latency));
+        for (std::map<const Value *, SUnit *>::iterator I = MemDefs.begin(),
+             E = MemDefs.end(); I != E; ++I)
+          I->second->addPred(SDep(SU, SDep::Order, SU->Latency));
         PendingLoads.push_back(SU);
       }
     }





More information about the llvm-commits mailing list