mirror of
				https://github.com/c64scene-ar/llvm-6502.git
				synced 2025-11-04 05:17:07 +00:00 
			
		
		
		
	time performance win in most cases. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@41126 91177308-0d34-0410-b5e6-96231b3b80d8
		
			
				
	
	
		
			438 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			438 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
//===- MemoryDependenceAnalysis.cpp - Mem Deps Implementation  --*- C++ -*-===//
 | 
						|
//
 | 
						|
//                     The LLVM Compiler Infrastructure
 | 
						|
//
 | 
						|
// This file was developed by the Owen Anderson and is distributed under
 | 
						|
// the University of Illinois Open Source License. See LICENSE.TXT for details.
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
//
 | 
						|
// This file implements an analysis that determines, for a given memory
 | 
						|
// operation, what preceding memory operations it depends on.  It builds on 
 | 
						|
// alias analysis information, and tries to provide a lazy, caching interface to
 | 
						|
// a common kind of alias information query.
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
#include "llvm/Analysis/MemoryDependenceAnalysis.h"
 | 
						|
#include "llvm/Constants.h"
 | 
						|
#include "llvm/Instructions.h"
 | 
						|
#include "llvm/Function.h"
 | 
						|
#include "llvm/Analysis/AliasAnalysis.h"
 | 
						|
#include "llvm/Support/CFG.h"
 | 
						|
#include "llvm/Target/TargetData.h"
 | 
						|
 | 
						|
using namespace llvm;
 | 
						|
 | 
						|
char MemoryDependenceAnalysis::ID = 0;
 | 
						|
  
 | 
						|
Instruction* const MemoryDependenceAnalysis::NonLocal = (Instruction*)-3;
 | 
						|
Instruction* const MemoryDependenceAnalysis::None = (Instruction*)-4;
 | 
						|
  
 | 
						|
// Register this pass...
 | 
						|
static RegisterPass<MemoryDependenceAnalysis> X("memdep",
 | 
						|
                                                "Memory Dependence Analysis");
 | 
						|
 | 
						|
/// getAnalysisUsage - Does not modify anything.  It uses Alias Analysis.
 | 
						|
///
 | 
						|
void MemoryDependenceAnalysis::getAnalysisUsage(AnalysisUsage &AU) const {
 | 
						|
  AU.setPreservesAll();
 | 
						|
  AU.addRequiredTransitive<AliasAnalysis>();
 | 
						|
  AU.addRequiredTransitive<TargetData>();
 | 
						|
}
 | 
						|
 | 
						|
/// getCallSiteDependency - Private helper for finding the local dependencies
 | 
						|
/// of a call site.
 | 
						|
Instruction* MemoryDependenceAnalysis::getCallSiteDependency(CallSite C,
 | 
						|
                                                           Instruction* start,
 | 
						|
                                                            BasicBlock* block) {
 | 
						|
  
 | 
						|
  AliasAnalysis& AA = getAnalysis<AliasAnalysis>();
 | 
						|
  TargetData& TD = getAnalysis<TargetData>();
 | 
						|
  BasicBlock::iterator blockBegin = C.getInstruction()->getParent()->begin();
 | 
						|
  BasicBlock::iterator QI = C.getInstruction();
 | 
						|
  
 | 
						|
  // If the starting point was specifiy, use it
 | 
						|
  if (start) {
 | 
						|
    QI = start;
 | 
						|
    blockBegin = start->getParent()->end();
 | 
						|
  // If the starting point wasn't specified, but the block was, use it
 | 
						|
  } else if (!start && block) {
 | 
						|
    QI = block->end();
 | 
						|
    blockBegin = block->end();
 | 
						|
  }
 | 
						|
  
 | 
						|
  // Walk backwards through the block, looking for dependencies
 | 
						|
  while (QI != blockBegin) {
 | 
						|
    --QI;
 | 
						|
    
 | 
						|
    // If this inst is a memory op, get the pointer it accessed
 | 
						|
    Value* pointer = 0;
 | 
						|
    uint64_t pointerSize = 0;
 | 
						|
    if (StoreInst* S = dyn_cast<StoreInst>(QI)) {
 | 
						|
      pointer = S->getPointerOperand();
 | 
						|
      pointerSize = TD.getTypeSize(S->getOperand(0)->getType());
 | 
						|
    } else if (LoadInst* L = dyn_cast<LoadInst>(QI)) {
 | 
						|
      pointer = L->getPointerOperand();
 | 
						|
      pointerSize = TD.getTypeSize(L->getType());
 | 
						|
    } else if (AllocationInst* AI = dyn_cast<AllocationInst>(QI)) {
 | 
						|
      pointer = AI;
 | 
						|
      if (ConstantInt* C = dyn_cast<ConstantInt>(AI->getArraySize()))
 | 
						|
        pointerSize = C->getZExtValue() * \
 | 
						|
                      TD.getTypeSize(AI->getAllocatedType());
 | 
						|
      else
 | 
						|
        pointerSize = ~0UL;
 | 
						|
    } else if (VAArgInst* V = dyn_cast<VAArgInst>(QI)) {
 | 
						|
      pointer = V->getOperand(0);
 | 
						|
      pointerSize = TD.getTypeSize(V->getType());
 | 
						|
    } else if (FreeInst* F = dyn_cast<FreeInst>(QI)) {
 | 
						|
      pointer = F->getPointerOperand();
 | 
						|
      
 | 
						|
      // FreeInsts erase the entire structure
 | 
						|
      pointerSize = ~0UL;
 | 
						|
    } else if (CallSite::get(QI).getInstruction() != 0) {
 | 
						|
      if (AA.getModRefInfo(C, CallSite::get(QI)) != AliasAnalysis::NoModRef) {
 | 
						|
        if (!start && !block) {
 | 
						|
          depGraphLocal.insert(std::make_pair(C.getInstruction(),
 | 
						|
                                              std::make_pair(QI, true)));
 | 
						|
          reverseDep[QI].insert(C.getInstruction());
 | 
						|
        }
 | 
						|
        return QI;
 | 
						|
      } else {
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
    } else
 | 
						|
      continue;
 | 
						|
    
 | 
						|
    if (AA.getModRefInfo(C, pointer, pointerSize) != AliasAnalysis::NoModRef) {
 | 
						|
      if (!start && !block) {
 | 
						|
        depGraphLocal.insert(std::make_pair(C.getInstruction(),
 | 
						|
                                            std::make_pair(QI, true)));
 | 
						|
        reverseDep[QI].insert(C.getInstruction());
 | 
						|
      }
 | 
						|
      return QI;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  
 | 
						|
  // No dependence found
 | 
						|
  depGraphLocal.insert(std::make_pair(C.getInstruction(),
 | 
						|
                                      std::make_pair(NonLocal, true)));
 | 
						|
  reverseDep[NonLocal].insert(C.getInstruction());
 | 
						|
  return NonLocal;
 | 
						|
}
 | 
						|
 | 
						|
/// nonLocalHelper - Private helper used to calculate non-local dependencies
 | 
						|
/// by doing DFS on the predecessors of a block to find its dependencies
 | 
						|
void MemoryDependenceAnalysis::nonLocalHelper(Instruction* query,
 | 
						|
                                              BasicBlock* block,
 | 
						|
                                         DenseMap<BasicBlock*, Value*>& resp) {
 | 
						|
  // Set of blocks that we've already visited in our DFS
 | 
						|
  SmallPtrSet<BasicBlock*, 4> visited;
 | 
						|
  // Current stack of the DFS
 | 
						|
  SmallVector<BasicBlock*, 4> stack;
 | 
						|
  stack.push_back(block);
 | 
						|
  
 | 
						|
  // Do a basic DFS
 | 
						|
  while (!stack.empty()) {
 | 
						|
    BasicBlock* BB = stack.back();
 | 
						|
    
 | 
						|
    // If we've already visited this block, no need to revist
 | 
						|
    if (visited.count(BB)) {
 | 
						|
      stack.pop_back();
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
    
 | 
						|
    // If we find a new block with a local dependency for query,
 | 
						|
    // then we insert the new dependency and backtrack.
 | 
						|
    if (BB != block) {
 | 
						|
      visited.insert(BB);
 | 
						|
      
 | 
						|
      Instruction* localDep = getDependency(query, 0, BB);
 | 
						|
      if (localDep != NonLocal) {
 | 
						|
        resp.insert(std::make_pair(BB, localDep));
 | 
						|
        stack.pop_back();
 | 
						|
        
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
    // If we re-encounter the starting block, we still need to search it
 | 
						|
    // because there might be a dependency in the starting block AFTER
 | 
						|
    // the position of the query.  This is necessary to get loops right.
 | 
						|
    } else if (BB == block && stack.size() > 1) {
 | 
						|
      visited.insert(BB);
 | 
						|
      
 | 
						|
      Instruction* localDep = getDependency(query, 0, BB);
 | 
						|
      if (localDep != query)
 | 
						|
        resp.insert(std::make_pair(BB, localDep));
 | 
						|
      
 | 
						|
      stack.pop_back();
 | 
						|
      
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
    
 | 
						|
    // If we didn't find anything, recurse on the precessors of this block
 | 
						|
    bool predOnStack = false;
 | 
						|
    bool inserted = false;
 | 
						|
    for (pred_iterator PI = pred_begin(BB), PE = pred_end(BB);
 | 
						|
         PI != PE; ++PI)
 | 
						|
      if (!visited.count(*PI)) {
 | 
						|
        stack.push_back(*PI);
 | 
						|
        inserted = true;
 | 
						|
      } else
 | 
						|
        predOnStack = true;
 | 
						|
    
 | 
						|
    // If we inserted a new predecessor, then we'll come back to this block
 | 
						|
    if (inserted)
 | 
						|
      continue;
 | 
						|
    // If we didn't insert because we have no predecessors, then this
 | 
						|
    // query has no dependency at all.
 | 
						|
    else if (!inserted && !predOnStack) {
 | 
						|
      resp.insert(std::make_pair(BB, None));
 | 
						|
    // If we didn't insert because our predecessors are already on the stack,
 | 
						|
    // then we might still have a dependency, but it will be discovered during
 | 
						|
    // backtracking.
 | 
						|
    } else if (!inserted && predOnStack){
 | 
						|
      resp.insert(std::make_pair(BB, NonLocal));
 | 
						|
    }
 | 
						|
    
 | 
						|
    stack.pop_back();
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/// getNonLocalDependency - Fills the passed-in map with the non-local 
 | 
						|
/// dependencies of the queries.  The map will contain NonLocal for
 | 
						|
/// blocks between the query and its dependencies.
 | 
						|
void MemoryDependenceAnalysis::getNonLocalDependency(Instruction* query,
 | 
						|
                                         DenseMap<BasicBlock*, Value*>& resp) {
 | 
						|
  if (depGraphNonLocal.count(query)) {
 | 
						|
    resp = depGraphNonLocal[query];
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  
 | 
						|
  // First check that we don't actually have a local dependency.
 | 
						|
  Instruction* localDep = getDependency(query);
 | 
						|
  if (localDep != NonLocal) {
 | 
						|
    resp.insert(std::make_pair(query->getParent(),localDep));
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  
 | 
						|
  // If not, go ahead and search for non-local ones.
 | 
						|
  nonLocalHelper(query, query->getParent(), resp);
 | 
						|
  
 | 
						|
  // Update the non-local dependency cache
 | 
						|
  for (DenseMap<BasicBlock*, Value*>::iterator I = resp.begin(), E = resp.end();
 | 
						|
       I != E; ++I) {
 | 
						|
    depGraphNonLocal[query].insert(*I);
 | 
						|
    reverseDepNonLocal[I->second].insert(query);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/// getDependency - Return the instruction on which a memory operation
 | 
						|
/// depends.  The local paramter indicates if the query should only
 | 
						|
/// evaluate dependencies within the same basic block.
 | 
						|
Instruction* MemoryDependenceAnalysis::getDependency(Instruction* query,
 | 
						|
                                                     Instruction* start,
 | 
						|
                                                     BasicBlock* block) {
 | 
						|
  // Start looking for dependencies with the queried inst
 | 
						|
  BasicBlock::iterator QI = query;
 | 
						|
  
 | 
						|
  // Check for a cached result
 | 
						|
  std::pair<Instruction*, bool> cachedResult = depGraphLocal[query];
 | 
						|
  // If we have a _confirmed_ cached entry, return it
 | 
						|
  if (cachedResult.second)
 | 
						|
    return cachedResult.first;
 | 
						|
  else if (cachedResult.first && cachedResult.first != NonLocal)
 | 
						|
  // If we have an unconfirmed cached entry, we can start our search from there
 | 
						|
    QI = cachedResult.first;
 | 
						|
  
 | 
						|
  if (start)
 | 
						|
    QI = start;
 | 
						|
  else if (!start && block)
 | 
						|
    QI = block->end();
 | 
						|
  
 | 
						|
  AliasAnalysis& AA = getAnalysis<AliasAnalysis>();
 | 
						|
  TargetData& TD = getAnalysis<TargetData>();
 | 
						|
  
 | 
						|
  // Get the pointer value for which dependence will be determined
 | 
						|
  Value* dependee = 0;
 | 
						|
  uint64_t dependeeSize = 0;
 | 
						|
  bool queryIsVolatile = false;
 | 
						|
  if (StoreInst* S = dyn_cast<StoreInst>(query)) {
 | 
						|
    dependee = S->getPointerOperand();
 | 
						|
    dependeeSize = TD.getTypeSize(S->getOperand(0)->getType());
 | 
						|
    queryIsVolatile = S->isVolatile();
 | 
						|
  } else if (LoadInst* L = dyn_cast<LoadInst>(query)) {
 | 
						|
    dependee = L->getPointerOperand();
 | 
						|
    dependeeSize = TD.getTypeSize(L->getType());
 | 
						|
    queryIsVolatile = L->isVolatile();
 | 
						|
  } else if (VAArgInst* V = dyn_cast<VAArgInst>(query)) {
 | 
						|
    dependee = V->getOperand(0);
 | 
						|
    dependeeSize = TD.getTypeSize(V->getType());
 | 
						|
  } else if (FreeInst* F = dyn_cast<FreeInst>(query)) {
 | 
						|
    dependee = F->getPointerOperand();
 | 
						|
    
 | 
						|
    // FreeInsts erase the entire structure, not just a field
 | 
						|
    dependeeSize = ~0UL;
 | 
						|
  } else if (CallSite::get(query).getInstruction() != 0)
 | 
						|
    return getCallSiteDependency(CallSite::get(query), start, block);
 | 
						|
  else if (isa<AllocationInst>(query))
 | 
						|
    return None;
 | 
						|
  else
 | 
						|
    return None;
 | 
						|
  
 | 
						|
  BasicBlock::iterator blockBegin = block ? block->begin()
 | 
						|
                                          : query->getParent()->begin();
 | 
						|
  
 | 
						|
  // Walk backwards through the basic block, looking for dependencies
 | 
						|
  while (QI != blockBegin) {
 | 
						|
    --QI;
 | 
						|
    
 | 
						|
    // If this inst is a memory op, get the pointer it accessed
 | 
						|
    Value* pointer = 0;
 | 
						|
    uint64_t pointerSize = 0;
 | 
						|
    if (StoreInst* S = dyn_cast<StoreInst>(QI)) {
 | 
						|
      // All volatile loads/stores depend on each other
 | 
						|
      if (queryIsVolatile && S->isVolatile()) {
 | 
						|
        if (!start && !block) {
 | 
						|
          depGraphLocal.insert(std::make_pair(query, std::make_pair(S, true)));
 | 
						|
          reverseDep[S].insert(query);
 | 
						|
        }
 | 
						|
        
 | 
						|
        return S;
 | 
						|
      }
 | 
						|
      
 | 
						|
      pointer = S->getPointerOperand();
 | 
						|
      pointerSize = TD.getTypeSize(S->getOperand(0)->getType());
 | 
						|
    } else if (LoadInst* L = dyn_cast<LoadInst>(QI)) {
 | 
						|
      // All volatile loads/stores depend on each other
 | 
						|
      if (queryIsVolatile && L->isVolatile()) {
 | 
						|
        if (!start && !block) {
 | 
						|
          depGraphLocal.insert(std::make_pair(query, std::make_pair(L, true)));
 | 
						|
          reverseDep[L].insert(query);
 | 
						|
        }
 | 
						|
        
 | 
						|
        return L;
 | 
						|
      }
 | 
						|
      
 | 
						|
      pointer = L->getPointerOperand();
 | 
						|
      pointerSize = TD.getTypeSize(L->getType());
 | 
						|
    } else if (AllocationInst* AI = dyn_cast<AllocationInst>(QI)) {
 | 
						|
      pointer = AI;
 | 
						|
      if (ConstantInt* C = dyn_cast<ConstantInt>(AI->getArraySize()))
 | 
						|
        pointerSize = C->getZExtValue() * \
 | 
						|
                      TD.getTypeSize(AI->getAllocatedType());
 | 
						|
      else
 | 
						|
        pointerSize = ~0UL;
 | 
						|
    } else if (VAArgInst* V = dyn_cast<VAArgInst>(QI)) {
 | 
						|
      pointer = V->getOperand(0);
 | 
						|
      pointerSize = TD.getTypeSize(V->getType());
 | 
						|
    } else if (FreeInst* F = dyn_cast<FreeInst>(QI)) {
 | 
						|
      pointer = F->getPointerOperand();
 | 
						|
      
 | 
						|
      // FreeInsts erase the entire structure
 | 
						|
      pointerSize = ~0UL;
 | 
						|
    } else if (CallSite::get(QI).getInstruction() != 0) {
 | 
						|
      // Call insts need special handling. Check if they can modify our pointer
 | 
						|
      AliasAnalysis::ModRefResult MR = AA.getModRefInfo(CallSite::get(QI),
 | 
						|
                                                      dependee, dependeeSize);
 | 
						|
      
 | 
						|
      if (MR != AliasAnalysis::NoModRef) {
 | 
						|
        // Loads don't depend on read-only calls
 | 
						|
        if (isa<LoadInst>(query) && MR == AliasAnalysis::Ref)
 | 
						|
          continue;
 | 
						|
        
 | 
						|
        if (!start && !block) {
 | 
						|
          depGraphLocal.insert(std::make_pair(query,
 | 
						|
                                              std::make_pair(QI, true)));
 | 
						|
          reverseDep[QI].insert(query);
 | 
						|
        }
 | 
						|
        
 | 
						|
        return QI;
 | 
						|
      } else {
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    
 | 
						|
    // If we found a pointer, check if it could be the same as our pointer
 | 
						|
    if (pointer) {
 | 
						|
      AliasAnalysis::AliasResult R = AA.alias(pointer, pointerSize,
 | 
						|
                                              dependee, dependeeSize);
 | 
						|
      
 | 
						|
      if (R != AliasAnalysis::NoAlias) {
 | 
						|
        // May-alias loads don't depend on each other
 | 
						|
        if (isa<LoadInst>(query) && isa<LoadInst>(QI) &&
 | 
						|
            R == AliasAnalysis::MayAlias)
 | 
						|
          continue;
 | 
						|
        
 | 
						|
        if (!start && !block) {
 | 
						|
          depGraphLocal.insert(std::make_pair(query,
 | 
						|
                                              std::make_pair(QI, true)));
 | 
						|
          reverseDep[QI].insert(query);
 | 
						|
        }
 | 
						|
        
 | 
						|
        return QI;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  
 | 
						|
  // If we found nothing, return the non-local flag
 | 
						|
  if (!start && !block) {
 | 
						|
    depGraphLocal.insert(std::make_pair(query,
 | 
						|
                                        std::make_pair(NonLocal, true)));
 | 
						|
    reverseDep[NonLocal].insert(query);
 | 
						|
  }
 | 
						|
  
 | 
						|
  return NonLocal;
 | 
						|
}
 | 
						|
 | 
						|
/// removeInstruction - Remove an instruction from the dependence analysis,
 | 
						|
/// updating the dependence of instructions that previously depended on it.
 | 
						|
/// This method attempts to keep the cache coherent using the reverse map.
 | 
						|
void MemoryDependenceAnalysis::removeInstruction(Instruction* rem) {
 | 
						|
  // Figure out the new dep for things that currently depend on rem
 | 
						|
  Instruction* newDep = NonLocal;
 | 
						|
 | 
						|
  depMapType::iterator depGraphEntry = depGraphLocal.find(rem);
 | 
						|
 | 
						|
  if (depGraphEntry != depGraphLocal.end()) {
 | 
						|
    if (depGraphEntry->second.first != NonLocal &&
 | 
						|
        depGraphEntry->second.second) {
 | 
						|
      // If we have dep info for rem, set them to it
 | 
						|
      BasicBlock::iterator RI = depGraphEntry->second.first;
 | 
						|
      RI++;
 | 
						|
      newDep = RI;
 | 
						|
    } else if (depGraphEntry->second.first == NonLocal &&
 | 
						|
               depGraphEntry->second.second ) {
 | 
						|
      // If we have a confirmed non-local flag, use it
 | 
						|
      newDep = NonLocal;
 | 
						|
    } else {
 | 
						|
      // Otherwise, use the immediate successor of rem
 | 
						|
      // NOTE: This is because, when getDependence is called, it will first
 | 
						|
      // check the immediate predecessor of what is in the cache.
 | 
						|
      BasicBlock::iterator RI = rem;
 | 
						|
      RI++;
 | 
						|
      newDep = RI;
 | 
						|
    }
 | 
						|
    
 | 
						|
    SmallPtrSet<Instruction*, 4>& set = reverseDep[rem];
 | 
						|
    for (SmallPtrSet<Instruction*, 4>::iterator I = set.begin(), E = set.end();
 | 
						|
         I != E; ++I) {
 | 
						|
      // Insert the new dependencies
 | 
						|
      // Mark it as unconfirmed as long as it is not the non-local flag
 | 
						|
      depGraphLocal[*I] = std::make_pair(newDep, !newDep);
 | 
						|
    }
 | 
						|
    
 | 
						|
    reverseDep.erase(rem);
 | 
						|
  }
 | 
						|
  
 | 
						|
  if (depGraphNonLocal.count(rem)) {
 | 
						|
    SmallPtrSet<Instruction*, 4>& set = reverseDepNonLocal[rem];
 | 
						|
    for (SmallPtrSet<Instruction*, 4>::iterator I = set.begin(), E = set.end();
 | 
						|
         I != E; ++I)
 | 
						|
      depGraphNonLocal.erase(*I);
 | 
						|
    
 | 
						|
    reverseDepNonLocal.erase(rem);
 | 
						|
  }
 | 
						|
 | 
						|
  getAnalysis<AliasAnalysis>().deleteValue(rem);
 | 
						|
}
 |