1586 lines
		
	
	
		
			62 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			1586 lines
		
	
	
		
			62 KiB
		
	
	
	
		
			C++
		
	
	
	
//===- MemorySSA.cpp - Unit tests for MemorySSA ---------------------------===//
 | 
						|
//
 | 
						|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 | 
						|
// See https://llvm.org/LICENSE.txt for license information.
 | 
						|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
#include "llvm/Analysis/MemorySSA.h"
 | 
						|
#include "llvm/Analysis/AliasAnalysis.h"
 | 
						|
#include "llvm/Analysis/BasicAliasAnalysis.h"
 | 
						|
#include "llvm/Analysis/MemorySSAUpdater.h"
 | 
						|
#include "llvm/IR/BasicBlock.h"
 | 
						|
#include "llvm/IR/DataLayout.h"
 | 
						|
#include "llvm/IR/Dominators.h"
 | 
						|
#include "llvm/IR/IRBuilder.h"
 | 
						|
#include "llvm/IR/Instructions.h"
 | 
						|
#include "llvm/IR/LLVMContext.h"
 | 
						|
#include "gtest/gtest.h"
 | 
						|
 | 
						|
using namespace llvm;
 | 
						|
 | 
						|
const static char DLString[] = "e-i64:64-f80:128-n8:16:32:64-S128";
 | 
						|
 | 
						|
/// There's a lot of common setup between these tests. This fixture helps reduce
 | 
						|
/// that. Tests should mock up a function, store it in F, and then call
 | 
						|
/// setupAnalyses().
 | 
						|
class MemorySSATest : public testing::Test {
 | 
						|
protected:
 | 
						|
  // N.B. Many of these members depend on each other (e.g. the Module depends on
 | 
						|
  // the Context, etc.). So, order matters here (and in TestAnalyses).
 | 
						|
  LLVMContext C;
 | 
						|
  Module M;
 | 
						|
  IRBuilder<> B;
 | 
						|
  DataLayout DL;
 | 
						|
  TargetLibraryInfoImpl TLII;
 | 
						|
  TargetLibraryInfo TLI;
 | 
						|
  Function *F;
 | 
						|
 | 
						|
  // Things that we need to build after the function is created.
 | 
						|
  struct TestAnalyses {
 | 
						|
    DominatorTree DT;
 | 
						|
    AssumptionCache AC;
 | 
						|
    AAResults AA;
 | 
						|
    BasicAAResult BAA;
 | 
						|
    // We need to defer MSSA construction until AA is *entirely* set up, which
 | 
						|
    // requires calling addAAResult. Hence, we just use a pointer here.
 | 
						|
    std::unique_ptr<MemorySSA> MSSA;
 | 
						|
    MemorySSAWalker *Walker;
 | 
						|
 | 
						|
    TestAnalyses(MemorySSATest &Test)
 | 
						|
        : DT(*Test.F), AC(*Test.F), AA(Test.TLI),
 | 
						|
          BAA(Test.DL, *Test.F, Test.TLI, AC, &DT) {
 | 
						|
      AA.addAAResult(BAA);
 | 
						|
      MSSA = make_unique<MemorySSA>(*Test.F, &AA, &DT);
 | 
						|
      Walker = MSSA->getWalker();
 | 
						|
    }
 | 
						|
  };
 | 
						|
 | 
						|
  std::unique_ptr<TestAnalyses> Analyses;
 | 
						|
 | 
						|
  void setupAnalyses() {
 | 
						|
    assert(F);
 | 
						|
    Analyses.reset(new TestAnalyses(*this));
 | 
						|
  }
 | 
						|
 | 
						|
public:
 | 
						|
  MemorySSATest()
 | 
						|
      : M("MemorySSATest", C), B(C), DL(DLString), TLI(TLII), F(nullptr) {}
 | 
						|
};
 | 
						|
 | 
						|
TEST_F(MemorySSATest, CreateALoad) {
 | 
						|
  // We create a diamond where there is a store on one side, and then after
 | 
						|
  // building MemorySSA, create a load after the merge point, and use it to test
 | 
						|
  // updating by creating an access for the load.
 | 
						|
  F = Function::Create(
 | 
						|
      FunctionType::get(B.getVoidTy(), {B.getInt8PtrTy()}, false),
 | 
						|
      GlobalValue::ExternalLinkage, "F", &M);
 | 
						|
  BasicBlock *Entry(BasicBlock::Create(C, "", F));
 | 
						|
  BasicBlock *Left(BasicBlock::Create(C, "", F));
 | 
						|
  BasicBlock *Right(BasicBlock::Create(C, "", F));
 | 
						|
  BasicBlock *Merge(BasicBlock::Create(C, "", F));
 | 
						|
  B.SetInsertPoint(Entry);
 | 
						|
  B.CreateCondBr(B.getTrue(), Left, Right);
 | 
						|
  B.SetInsertPoint(Left);
 | 
						|
  Argument *PointerArg = &*F->arg_begin();
 | 
						|
  B.CreateStore(B.getInt8(16), PointerArg);
 | 
						|
  BranchInst::Create(Merge, Left);
 | 
						|
  BranchInst::Create(Merge, Right);
 | 
						|
 | 
						|
  setupAnalyses();
 | 
						|
  MemorySSA &MSSA = *Analyses->MSSA;
 | 
						|
  MemorySSAUpdater Updater(&MSSA);
 | 
						|
  // Add the load
 | 
						|
  B.SetInsertPoint(Merge);
 | 
						|
  LoadInst *LoadInst = B.CreateLoad(B.getInt8Ty(), PointerArg);
 | 
						|
 | 
						|
  // MemoryPHI should already exist.
 | 
						|
  MemoryPhi *MP = MSSA.getMemoryAccess(Merge);
 | 
						|
  EXPECT_NE(MP, nullptr);
 | 
						|
 | 
						|
  // Create the load memory acccess
 | 
						|
  MemoryUse *LoadAccess = cast<MemoryUse>(Updater.createMemoryAccessInBB(
 | 
						|
      LoadInst, MP, Merge, MemorySSA::Beginning));
 | 
						|
  MemoryAccess *DefiningAccess = LoadAccess->getDefiningAccess();
 | 
						|
  EXPECT_TRUE(isa<MemoryPhi>(DefiningAccess));
 | 
						|
  MSSA.verifyMemorySSA();
 | 
						|
}
 | 
						|
TEST_F(MemorySSATest, CreateLoadsAndStoreUpdater) {
 | 
						|
  // We create a diamond, then build memoryssa with no memory accesses, and
 | 
						|
  // incrementally update it by inserting a store in the, entry, a load in the
 | 
						|
  // merge point, then a store in the branch, another load in the merge point,
 | 
						|
  // and then a store in the entry.
 | 
						|
  F = Function::Create(
 | 
						|
      FunctionType::get(B.getVoidTy(), {B.getInt8PtrTy()}, false),
 | 
						|
      GlobalValue::ExternalLinkage, "F", &M);
 | 
						|
  BasicBlock *Entry(BasicBlock::Create(C, "", F));
 | 
						|
  BasicBlock *Left(BasicBlock::Create(C, "", F));
 | 
						|
  BasicBlock *Right(BasicBlock::Create(C, "", F));
 | 
						|
  BasicBlock *Merge(BasicBlock::Create(C, "", F));
 | 
						|
  B.SetInsertPoint(Entry);
 | 
						|
  B.CreateCondBr(B.getTrue(), Left, Right);
 | 
						|
  B.SetInsertPoint(Left, Left->begin());
 | 
						|
  Argument *PointerArg = &*F->arg_begin();
 | 
						|
  B.SetInsertPoint(Left);
 | 
						|
  B.CreateBr(Merge);
 | 
						|
  B.SetInsertPoint(Right);
 | 
						|
  B.CreateBr(Merge);
 | 
						|
 | 
						|
  setupAnalyses();
 | 
						|
  MemorySSA &MSSA = *Analyses->MSSA;
 | 
						|
  MemorySSAUpdater Updater(&MSSA);
 | 
						|
  // Add the store
 | 
						|
  B.SetInsertPoint(Entry, Entry->begin());
 | 
						|
  StoreInst *EntryStore = B.CreateStore(B.getInt8(16), PointerArg);
 | 
						|
  MemoryAccess *EntryStoreAccess = Updater.createMemoryAccessInBB(
 | 
						|
      EntryStore, nullptr, Entry, MemorySSA::Beginning);
 | 
						|
  Updater.insertDef(cast<MemoryDef>(EntryStoreAccess));
 | 
						|
 | 
						|
  // Add the load
 | 
						|
  B.SetInsertPoint(Merge, Merge->begin());
 | 
						|
  LoadInst *FirstLoad = B.CreateLoad(B.getInt8Ty(), PointerArg);
 | 
						|
 | 
						|
  // MemoryPHI should not already exist.
 | 
						|
  MemoryPhi *MP = MSSA.getMemoryAccess(Merge);
 | 
						|
  EXPECT_EQ(MP, nullptr);
 | 
						|
 | 
						|
  // Create the load memory access
 | 
						|
  MemoryUse *FirstLoadAccess = cast<MemoryUse>(Updater.createMemoryAccessInBB(
 | 
						|
      FirstLoad, nullptr, Merge, MemorySSA::Beginning));
 | 
						|
  Updater.insertUse(FirstLoadAccess);
 | 
						|
  // Should just have a load using the entry access, because it should discover
 | 
						|
  // the phi is trivial
 | 
						|
  EXPECT_EQ(FirstLoadAccess->getDefiningAccess(), EntryStoreAccess);
 | 
						|
 | 
						|
  // Create a store on the left
 | 
						|
  // Add the store
 | 
						|
  B.SetInsertPoint(Left, Left->begin());
 | 
						|
  StoreInst *LeftStore = B.CreateStore(B.getInt8(16), PointerArg);
 | 
						|
  MemoryAccess *LeftStoreAccess = Updater.createMemoryAccessInBB(
 | 
						|
      LeftStore, nullptr, Left, MemorySSA::Beginning);
 | 
						|
  Updater.insertDef(cast<MemoryDef>(LeftStoreAccess), false);
 | 
						|
 | 
						|
  // MemoryPHI should exist after adding LeftStore.
 | 
						|
  MP = MSSA.getMemoryAccess(Merge);
 | 
						|
  EXPECT_NE(MP, nullptr);
 | 
						|
 | 
						|
  // Add the second load
 | 
						|
  B.SetInsertPoint(Merge, Merge->begin());
 | 
						|
  LoadInst *SecondLoad = B.CreateLoad(B.getInt8Ty(), PointerArg);
 | 
						|
 | 
						|
  // Create the load memory access
 | 
						|
  MemoryUse *SecondLoadAccess = cast<MemoryUse>(Updater.createMemoryAccessInBB(
 | 
						|
      SecondLoad, nullptr, Merge, MemorySSA::Beginning));
 | 
						|
  Updater.insertUse(SecondLoadAccess);
 | 
						|
  // Now the load should be a phi of the entry store and the left store
 | 
						|
  MemoryPhi *MergePhi =
 | 
						|
      dyn_cast<MemoryPhi>(SecondLoadAccess->getDefiningAccess());
 | 
						|
  EXPECT_NE(MergePhi, nullptr);
 | 
						|
  EXPECT_EQ(MergePhi->getIncomingValue(0), EntryStoreAccess);
 | 
						|
  EXPECT_EQ(MergePhi->getIncomingValue(1), LeftStoreAccess);
 | 
						|
  // Now create a store below the existing one in the entry
 | 
						|
  B.SetInsertPoint(Entry, --Entry->end());
 | 
						|
  StoreInst *SecondEntryStore = B.CreateStore(B.getInt8(16), PointerArg);
 | 
						|
  MemoryAccess *SecondEntryStoreAccess = Updater.createMemoryAccessInBB(
 | 
						|
      SecondEntryStore, nullptr, Entry, MemorySSA::End);
 | 
						|
  // Insert it twice just to test renaming
 | 
						|
  Updater.insertDef(cast<MemoryDef>(SecondEntryStoreAccess), false);
 | 
						|
  EXPECT_NE(FirstLoadAccess->getDefiningAccess(), MergePhi);
 | 
						|
  Updater.insertDef(cast<MemoryDef>(SecondEntryStoreAccess), true);
 | 
						|
  EXPECT_EQ(FirstLoadAccess->getDefiningAccess(), MergePhi);
 | 
						|
  // and make sure the phi below it got updated, despite being blocks away
 | 
						|
  MergePhi = dyn_cast<MemoryPhi>(SecondLoadAccess->getDefiningAccess());
 | 
						|
  EXPECT_NE(MergePhi, nullptr);
 | 
						|
  EXPECT_EQ(MergePhi->getIncomingValue(0), SecondEntryStoreAccess);
 | 
						|
  EXPECT_EQ(MergePhi->getIncomingValue(1), LeftStoreAccess);
 | 
						|
  MSSA.verifyMemorySSA();
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(MemorySSATest, CreateALoadUpdater) {
 | 
						|
  // We create a diamond, then build memoryssa with no memory accesses, and
 | 
						|
  // incrementally update it by inserting a store in one of the branches, and a
 | 
						|
  // load in the merge point
 | 
						|
  F = Function::Create(
 | 
						|
      FunctionType::get(B.getVoidTy(), {B.getInt8PtrTy()}, false),
 | 
						|
      GlobalValue::ExternalLinkage, "F", &M);
 | 
						|
  BasicBlock *Entry(BasicBlock::Create(C, "", F));
 | 
						|
  BasicBlock *Left(BasicBlock::Create(C, "", F));
 | 
						|
  BasicBlock *Right(BasicBlock::Create(C, "", F));
 | 
						|
  BasicBlock *Merge(BasicBlock::Create(C, "", F));
 | 
						|
  B.SetInsertPoint(Entry);
 | 
						|
  B.CreateCondBr(B.getTrue(), Left, Right);
 | 
						|
  B.SetInsertPoint(Left, Left->begin());
 | 
						|
  Argument *PointerArg = &*F->arg_begin();
 | 
						|
  B.SetInsertPoint(Left);
 | 
						|
  B.CreateBr(Merge);
 | 
						|
  B.SetInsertPoint(Right);
 | 
						|
  B.CreateBr(Merge);
 | 
						|
 | 
						|
  setupAnalyses();
 | 
						|
  MemorySSA &MSSA = *Analyses->MSSA;
 | 
						|
  MemorySSAUpdater Updater(&MSSA);
 | 
						|
  B.SetInsertPoint(Left, Left->begin());
 | 
						|
  // Add the store
 | 
						|
  StoreInst *SI = B.CreateStore(B.getInt8(16), PointerArg);
 | 
						|
  MemoryAccess *StoreAccess =
 | 
						|
      Updater.createMemoryAccessInBB(SI, nullptr, Left, MemorySSA::Beginning);
 | 
						|
  Updater.insertDef(cast<MemoryDef>(StoreAccess));
 | 
						|
 | 
						|
  // MemoryPHI should be created when inserting the def
 | 
						|
  MemoryPhi *MP = MSSA.getMemoryAccess(Merge);
 | 
						|
  EXPECT_NE(MP, nullptr);
 | 
						|
 | 
						|
  // Add the load
 | 
						|
  B.SetInsertPoint(Merge, Merge->begin());
 | 
						|
  LoadInst *LoadInst = B.CreateLoad(B.getInt8Ty(), PointerArg);
 | 
						|
 | 
						|
  // Create the load memory acccess
 | 
						|
  MemoryUse *LoadAccess = cast<MemoryUse>(Updater.createMemoryAccessInBB(
 | 
						|
      LoadInst, nullptr, Merge, MemorySSA::Beginning));
 | 
						|
  Updater.insertUse(LoadAccess);
 | 
						|
  MemoryAccess *DefiningAccess = LoadAccess->getDefiningAccess();
 | 
						|
  EXPECT_TRUE(isa<MemoryPhi>(DefiningAccess));
 | 
						|
  MSSA.verifyMemorySSA();
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(MemorySSATest, SinkLoad) {
 | 
						|
  F = Function::Create(
 | 
						|
      FunctionType::get(B.getVoidTy(), {B.getInt8PtrTy()}, false),
 | 
						|
      GlobalValue::ExternalLinkage, "F", &M);
 | 
						|
  BasicBlock *Entry(BasicBlock::Create(C, "", F));
 | 
						|
  BasicBlock *Left(BasicBlock::Create(C, "", F));
 | 
						|
  BasicBlock *Right(BasicBlock::Create(C, "", F));
 | 
						|
  BasicBlock *Merge(BasicBlock::Create(C, "", F));
 | 
						|
  B.SetInsertPoint(Entry);
 | 
						|
  B.CreateCondBr(B.getTrue(), Left, Right);
 | 
						|
  B.SetInsertPoint(Left, Left->begin());
 | 
						|
  Argument *PointerArg = &*F->arg_begin();
 | 
						|
  B.SetInsertPoint(Left);
 | 
						|
  B.CreateBr(Merge);
 | 
						|
  B.SetInsertPoint(Right);
 | 
						|
  B.CreateBr(Merge);
 | 
						|
 | 
						|
  // Load in left block
 | 
						|
  B.SetInsertPoint(Left, Left->begin());
 | 
						|
  LoadInst *LoadInst1 = B.CreateLoad(B.getInt8Ty(), PointerArg);
 | 
						|
  // Store in merge block
 | 
						|
  B.SetInsertPoint(Merge, Merge->begin());
 | 
						|
  B.CreateStore(B.getInt8(16), PointerArg);
 | 
						|
 | 
						|
  setupAnalyses();
 | 
						|
  MemorySSA &MSSA = *Analyses->MSSA;
 | 
						|
  MemorySSAUpdater Updater(&MSSA);
 | 
						|
 | 
						|
  // Mimic sinking of a load:
 | 
						|
  // - clone load
 | 
						|
  // - insert in "exit" block
 | 
						|
  // - insert in mssa
 | 
						|
  // - remove from original block
 | 
						|
 | 
						|
  LoadInst *LoadInstClone = cast<LoadInst>(LoadInst1->clone());
 | 
						|
  Merge->getInstList().insert(Merge->begin(), LoadInstClone);
 | 
						|
  MemoryAccess * NewLoadAccess =
 | 
						|
      Updater.createMemoryAccessInBB(LoadInstClone, nullptr,
 | 
						|
                                     LoadInstClone->getParent(),
 | 
						|
                                     MemorySSA::Beginning);
 | 
						|
  Updater.insertUse(cast<MemoryUse>(NewLoadAccess));
 | 
						|
  MSSA.verifyMemorySSA();
 | 
						|
  Updater.removeMemoryAccess(MSSA.getMemoryAccess(LoadInst1));
 | 
						|
  MSSA.verifyMemorySSA();
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(MemorySSATest, MoveAStore) {
 | 
						|
  // We create a diamond where there is a in the entry, a store on one side, and
 | 
						|
  // a load at the end.  After building MemorySSA, we test updating by moving
 | 
						|
  // the store from the side block to the entry block. This destroys the old
 | 
						|
  // access.
 | 
						|
  F = Function::Create(
 | 
						|
      FunctionType::get(B.getVoidTy(), {B.getInt8PtrTy()}, false),
 | 
						|
      GlobalValue::ExternalLinkage, "F", &M);
 | 
						|
  BasicBlock *Entry(BasicBlock::Create(C, "", F));
 | 
						|
  BasicBlock *Left(BasicBlock::Create(C, "", F));
 | 
						|
  BasicBlock *Right(BasicBlock::Create(C, "", F));
 | 
						|
  BasicBlock *Merge(BasicBlock::Create(C, "", F));
 | 
						|
  B.SetInsertPoint(Entry);
 | 
						|
  Argument *PointerArg = &*F->arg_begin();
 | 
						|
  StoreInst *EntryStore = B.CreateStore(B.getInt8(16), PointerArg);
 | 
						|
  B.CreateCondBr(B.getTrue(), Left, Right);
 | 
						|
  B.SetInsertPoint(Left);
 | 
						|
  StoreInst *SideStore = B.CreateStore(B.getInt8(16), PointerArg);
 | 
						|
  BranchInst::Create(Merge, Left);
 | 
						|
  BranchInst::Create(Merge, Right);
 | 
						|
  B.SetInsertPoint(Merge);
 | 
						|
  B.CreateLoad(B.getInt8Ty(), PointerArg);
 | 
						|
  setupAnalyses();
 | 
						|
  MemorySSA &MSSA = *Analyses->MSSA;
 | 
						|
  MemorySSAUpdater Updater(&MSSA);
 | 
						|
  // Move the store
 | 
						|
  SideStore->moveBefore(Entry->getTerminator());
 | 
						|
  MemoryAccess *EntryStoreAccess = MSSA.getMemoryAccess(EntryStore);
 | 
						|
  MemoryAccess *SideStoreAccess = MSSA.getMemoryAccess(SideStore);
 | 
						|
  MemoryAccess *NewStoreAccess = Updater.createMemoryAccessAfter(
 | 
						|
      SideStore, EntryStoreAccess, EntryStoreAccess);
 | 
						|
  EntryStoreAccess->replaceAllUsesWith(NewStoreAccess);
 | 
						|
  Updater.removeMemoryAccess(SideStoreAccess);
 | 
						|
  MSSA.verifyMemorySSA();
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(MemorySSATest, MoveAStoreUpdater) {
 | 
						|
  // We create a diamond where there is a in the entry, a store on one side, and
 | 
						|
  // a load at the end.  After building MemorySSA, we test updating by moving
 | 
						|
  // the store from the side block to the entry block.  This destroys the old
 | 
						|
  // access.
 | 
						|
  F = Function::Create(
 | 
						|
      FunctionType::get(B.getVoidTy(), {B.getInt8PtrTy()}, false),
 | 
						|
      GlobalValue::ExternalLinkage, "F", &M);
 | 
						|
  BasicBlock *Entry(BasicBlock::Create(C, "", F));
 | 
						|
  BasicBlock *Left(BasicBlock::Create(C, "", F));
 | 
						|
  BasicBlock *Right(BasicBlock::Create(C, "", F));
 | 
						|
  BasicBlock *Merge(BasicBlock::Create(C, "", F));
 | 
						|
  B.SetInsertPoint(Entry);
 | 
						|
  Argument *PointerArg = &*F->arg_begin();
 | 
						|
  StoreInst *EntryStore = B.CreateStore(B.getInt8(16), PointerArg);
 | 
						|
  B.CreateCondBr(B.getTrue(), Left, Right);
 | 
						|
  B.SetInsertPoint(Left);
 | 
						|
  auto *SideStore = B.CreateStore(B.getInt8(16), PointerArg);
 | 
						|
  BranchInst::Create(Merge, Left);
 | 
						|
  BranchInst::Create(Merge, Right);
 | 
						|
  B.SetInsertPoint(Merge);
 | 
						|
  auto *MergeLoad = B.CreateLoad(B.getInt8Ty(), PointerArg);
 | 
						|
  setupAnalyses();
 | 
						|
  MemorySSA &MSSA = *Analyses->MSSA;
 | 
						|
  MemorySSAUpdater Updater(&MSSA);
 | 
						|
 | 
						|
  // Move the store
 | 
						|
  SideStore->moveBefore(Entry->getTerminator());
 | 
						|
  auto *EntryStoreAccess = MSSA.getMemoryAccess(EntryStore);
 | 
						|
  auto *SideStoreAccess = MSSA.getMemoryAccess(SideStore);
 | 
						|
  auto *NewStoreAccess = Updater.createMemoryAccessAfter(
 | 
						|
      SideStore, EntryStoreAccess, EntryStoreAccess);
 | 
						|
  // Before, the load will point to a phi of the EntryStore and SideStore.
 | 
						|
  auto *LoadAccess = cast<MemoryUse>(MSSA.getMemoryAccess(MergeLoad));
 | 
						|
  EXPECT_TRUE(isa<MemoryPhi>(LoadAccess->getDefiningAccess()));
 | 
						|
  MemoryPhi *MergePhi = cast<MemoryPhi>(LoadAccess->getDefiningAccess());
 | 
						|
  EXPECT_EQ(MergePhi->getIncomingValue(1), EntryStoreAccess);
 | 
						|
  EXPECT_EQ(MergePhi->getIncomingValue(0), SideStoreAccess);
 | 
						|
  Updater.removeMemoryAccess(SideStoreAccess);
 | 
						|
  Updater.insertDef(cast<MemoryDef>(NewStoreAccess));
 | 
						|
  // After it's a phi of the new side store access.
 | 
						|
  EXPECT_EQ(MergePhi->getIncomingValue(0), NewStoreAccess);
 | 
						|
  EXPECT_EQ(MergePhi->getIncomingValue(1), NewStoreAccess);
 | 
						|
  MSSA.verifyMemorySSA();
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(MemorySSATest, MoveAStoreUpdaterMove) {
 | 
						|
  // We create a diamond where there is a in the entry, a store on one side, and
 | 
						|
  // a load at the end.  After building MemorySSA, we test updating by moving
 | 
						|
  // the store from the side block to the entry block.  This does not destroy
 | 
						|
  // the old access.
 | 
						|
  F = Function::Create(
 | 
						|
      FunctionType::get(B.getVoidTy(), {B.getInt8PtrTy()}, false),
 | 
						|
      GlobalValue::ExternalLinkage, "F", &M);
 | 
						|
  BasicBlock *Entry(BasicBlock::Create(C, "", F));
 | 
						|
  BasicBlock *Left(BasicBlock::Create(C, "", F));
 | 
						|
  BasicBlock *Right(BasicBlock::Create(C, "", F));
 | 
						|
  BasicBlock *Merge(BasicBlock::Create(C, "", F));
 | 
						|
  B.SetInsertPoint(Entry);
 | 
						|
  Argument *PointerArg = &*F->arg_begin();
 | 
						|
  StoreInst *EntryStore = B.CreateStore(B.getInt8(16), PointerArg);
 | 
						|
  B.CreateCondBr(B.getTrue(), Left, Right);
 | 
						|
  B.SetInsertPoint(Left);
 | 
						|
  auto *SideStore = B.CreateStore(B.getInt8(16), PointerArg);
 | 
						|
  BranchInst::Create(Merge, Left);
 | 
						|
  BranchInst::Create(Merge, Right);
 | 
						|
  B.SetInsertPoint(Merge);
 | 
						|
  auto *MergeLoad = B.CreateLoad(B.getInt8Ty(), PointerArg);
 | 
						|
  setupAnalyses();
 | 
						|
  MemorySSA &MSSA = *Analyses->MSSA;
 | 
						|
  MemorySSAUpdater Updater(&MSSA);
 | 
						|
 | 
						|
  // Move the store
 | 
						|
  auto *EntryStoreAccess = MSSA.getMemoryAccess(EntryStore);
 | 
						|
  auto *SideStoreAccess = MSSA.getMemoryAccess(SideStore);
 | 
						|
  // Before, the load will point to a phi of the EntryStore and SideStore.
 | 
						|
  auto *LoadAccess = cast<MemoryUse>(MSSA.getMemoryAccess(MergeLoad));
 | 
						|
  EXPECT_TRUE(isa<MemoryPhi>(LoadAccess->getDefiningAccess()));
 | 
						|
  MemoryPhi *MergePhi = cast<MemoryPhi>(LoadAccess->getDefiningAccess());
 | 
						|
  EXPECT_EQ(MergePhi->getIncomingValue(1), EntryStoreAccess);
 | 
						|
  EXPECT_EQ(MergePhi->getIncomingValue(0), SideStoreAccess);
 | 
						|
  SideStore->moveBefore(*EntryStore->getParent(), ++EntryStore->getIterator());
 | 
						|
  Updater.moveAfter(SideStoreAccess, EntryStoreAccess);
 | 
						|
  // After, it's a phi of the side store.
 | 
						|
  EXPECT_EQ(MergePhi->getIncomingValue(0), SideStoreAccess);
 | 
						|
  EXPECT_EQ(MergePhi->getIncomingValue(1), SideStoreAccess);
 | 
						|
 | 
						|
  MSSA.verifyMemorySSA();
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(MemorySSATest, MoveAStoreAllAround) {
 | 
						|
  // We create a diamond where there is a in the entry, a store on one side, and
 | 
						|
  // a load at the end.  After building MemorySSA, we test updating by moving
 | 
						|
  // the store from the side block to the entry block, then to the other side
 | 
						|
  // block, then to before the load.  This does not destroy the old access.
 | 
						|
  F = Function::Create(
 | 
						|
      FunctionType::get(B.getVoidTy(), {B.getInt8PtrTy()}, false),
 | 
						|
      GlobalValue::ExternalLinkage, "F", &M);
 | 
						|
  BasicBlock *Entry(BasicBlock::Create(C, "", F));
 | 
						|
  BasicBlock *Left(BasicBlock::Create(C, "", F));
 | 
						|
  BasicBlock *Right(BasicBlock::Create(C, "", F));
 | 
						|
  BasicBlock *Merge(BasicBlock::Create(C, "", F));
 | 
						|
  B.SetInsertPoint(Entry);
 | 
						|
  Argument *PointerArg = &*F->arg_begin();
 | 
						|
  StoreInst *EntryStore = B.CreateStore(B.getInt8(16), PointerArg);
 | 
						|
  B.CreateCondBr(B.getTrue(), Left, Right);
 | 
						|
  B.SetInsertPoint(Left);
 | 
						|
  auto *SideStore = B.CreateStore(B.getInt8(16), PointerArg);
 | 
						|
  BranchInst::Create(Merge, Left);
 | 
						|
  BranchInst::Create(Merge, Right);
 | 
						|
  B.SetInsertPoint(Merge);
 | 
						|
  auto *MergeLoad = B.CreateLoad(B.getInt8Ty(), PointerArg);
 | 
						|
  setupAnalyses();
 | 
						|
  MemorySSA &MSSA = *Analyses->MSSA;
 | 
						|
  MemorySSAUpdater Updater(&MSSA);
 | 
						|
 | 
						|
  // Move the store
 | 
						|
  auto *EntryStoreAccess = MSSA.getMemoryAccess(EntryStore);
 | 
						|
  auto *SideStoreAccess = MSSA.getMemoryAccess(SideStore);
 | 
						|
  // Before, the load will point to a phi of the EntryStore and SideStore.
 | 
						|
  auto *LoadAccess = cast<MemoryUse>(MSSA.getMemoryAccess(MergeLoad));
 | 
						|
  EXPECT_TRUE(isa<MemoryPhi>(LoadAccess->getDefiningAccess()));
 | 
						|
  MemoryPhi *MergePhi = cast<MemoryPhi>(LoadAccess->getDefiningAccess());
 | 
						|
  EXPECT_EQ(MergePhi->getIncomingValue(1), EntryStoreAccess);
 | 
						|
  EXPECT_EQ(MergePhi->getIncomingValue(0), SideStoreAccess);
 | 
						|
  // Move the store before the entry store
 | 
						|
  SideStore->moveBefore(*EntryStore->getParent(), EntryStore->getIterator());
 | 
						|
  Updater.moveBefore(SideStoreAccess, EntryStoreAccess);
 | 
						|
  // After, it's a phi of the entry store.
 | 
						|
  EXPECT_EQ(MergePhi->getIncomingValue(0), EntryStoreAccess);
 | 
						|
  EXPECT_EQ(MergePhi->getIncomingValue(1), EntryStoreAccess);
 | 
						|
  MSSA.verifyMemorySSA();
 | 
						|
  // Now move the store to the right branch
 | 
						|
  SideStore->moveBefore(*Right, Right->begin());
 | 
						|
  Updater.moveToPlace(SideStoreAccess, Right, MemorySSA::Beginning);
 | 
						|
  MSSA.verifyMemorySSA();
 | 
						|
  EXPECT_EQ(MergePhi->getIncomingValue(0), EntryStoreAccess);
 | 
						|
  EXPECT_EQ(MergePhi->getIncomingValue(1), SideStoreAccess);
 | 
						|
  // Now move it before the load
 | 
						|
  SideStore->moveBefore(MergeLoad);
 | 
						|
  Updater.moveBefore(SideStoreAccess, LoadAccess);
 | 
						|
  EXPECT_EQ(MergePhi->getIncomingValue(0), EntryStoreAccess);
 | 
						|
  EXPECT_EQ(MergePhi->getIncomingValue(1), EntryStoreAccess);
 | 
						|
  MSSA.verifyMemorySSA();
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(MemorySSATest, RemoveAPhi) {
 | 
						|
  // We create a diamond where there is a store on one side, and then a load
 | 
						|
  // after the merge point.  This enables us to test a bunch of different
 | 
						|
  // removal cases.
 | 
						|
  F = Function::Create(
 | 
						|
      FunctionType::get(B.getVoidTy(), {B.getInt8PtrTy()}, false),
 | 
						|
      GlobalValue::ExternalLinkage, "F", &M);
 | 
						|
  BasicBlock *Entry(BasicBlock::Create(C, "", F));
 | 
						|
  BasicBlock *Left(BasicBlock::Create(C, "", F));
 | 
						|
  BasicBlock *Right(BasicBlock::Create(C, "", F));
 | 
						|
  BasicBlock *Merge(BasicBlock::Create(C, "", F));
 | 
						|
  B.SetInsertPoint(Entry);
 | 
						|
  B.CreateCondBr(B.getTrue(), Left, Right);
 | 
						|
  B.SetInsertPoint(Left);
 | 
						|
  Argument *PointerArg = &*F->arg_begin();
 | 
						|
  StoreInst *StoreInst = B.CreateStore(B.getInt8(16), PointerArg);
 | 
						|
  BranchInst::Create(Merge, Left);
 | 
						|
  BranchInst::Create(Merge, Right);
 | 
						|
  B.SetInsertPoint(Merge);
 | 
						|
  LoadInst *LoadInst = B.CreateLoad(B.getInt8Ty(), PointerArg);
 | 
						|
 | 
						|
  setupAnalyses();
 | 
						|
  MemorySSA &MSSA = *Analyses->MSSA;
 | 
						|
  MemorySSAUpdater Updater(&MSSA);
 | 
						|
 | 
						|
  // Before, the load will be a use of a phi<store, liveonentry>.
 | 
						|
  MemoryUse *LoadAccess = cast<MemoryUse>(MSSA.getMemoryAccess(LoadInst));
 | 
						|
  MemoryDef *StoreAccess = cast<MemoryDef>(MSSA.getMemoryAccess(StoreInst));
 | 
						|
  MemoryAccess *DefiningAccess = LoadAccess->getDefiningAccess();
 | 
						|
  EXPECT_TRUE(isa<MemoryPhi>(DefiningAccess));
 | 
						|
  // Kill the store
 | 
						|
  Updater.removeMemoryAccess(StoreAccess);
 | 
						|
  MemoryPhi *MP = cast<MemoryPhi>(DefiningAccess);
 | 
						|
  // Verify the phi ended up as liveonentry, liveonentry
 | 
						|
  for (auto &Op : MP->incoming_values())
 | 
						|
    EXPECT_TRUE(MSSA.isLiveOnEntryDef(cast<MemoryAccess>(Op.get())));
 | 
						|
  // Replace the phi uses with the live on entry def
 | 
						|
  MP->replaceAllUsesWith(MSSA.getLiveOnEntryDef());
 | 
						|
  // Verify the load is now defined by liveOnEntryDef
 | 
						|
  EXPECT_TRUE(MSSA.isLiveOnEntryDef(LoadAccess->getDefiningAccess()));
 | 
						|
  // Remove the PHI
 | 
						|
  Updater.removeMemoryAccess(MP);
 | 
						|
  MSSA.verifyMemorySSA();
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(MemorySSATest, RemoveMemoryAccess) {
 | 
						|
  // We create a diamond where there is a store on one side, and then a load
 | 
						|
  // after the merge point.  This enables us to test a bunch of different
 | 
						|
  // removal cases.
 | 
						|
  F = Function::Create(
 | 
						|
      FunctionType::get(B.getVoidTy(), {B.getInt8PtrTy()}, false),
 | 
						|
      GlobalValue::ExternalLinkage, "F", &M);
 | 
						|
  BasicBlock *Entry(BasicBlock::Create(C, "", F));
 | 
						|
  BasicBlock *Left(BasicBlock::Create(C, "", F));
 | 
						|
  BasicBlock *Right(BasicBlock::Create(C, "", F));
 | 
						|
  BasicBlock *Merge(BasicBlock::Create(C, "", F));
 | 
						|
  B.SetInsertPoint(Entry);
 | 
						|
  B.CreateCondBr(B.getTrue(), Left, Right);
 | 
						|
  B.SetInsertPoint(Left);
 | 
						|
  Argument *PointerArg = &*F->arg_begin();
 | 
						|
  StoreInst *StoreInst = B.CreateStore(B.getInt8(16), PointerArg);
 | 
						|
  BranchInst::Create(Merge, Left);
 | 
						|
  BranchInst::Create(Merge, Right);
 | 
						|
  B.SetInsertPoint(Merge);
 | 
						|
  LoadInst *LoadInst = B.CreateLoad(B.getInt8Ty(), PointerArg);
 | 
						|
 | 
						|
  setupAnalyses();
 | 
						|
  MemorySSA &MSSA = *Analyses->MSSA;
 | 
						|
  MemorySSAWalker *Walker = Analyses->Walker;
 | 
						|
  MemorySSAUpdater Updater(&MSSA);
 | 
						|
 | 
						|
  // Before, the load will be a use of a phi<store, liveonentry>. It should be
 | 
						|
  // the same after.
 | 
						|
  MemoryUse *LoadAccess = cast<MemoryUse>(MSSA.getMemoryAccess(LoadInst));
 | 
						|
  MemoryDef *StoreAccess = cast<MemoryDef>(MSSA.getMemoryAccess(StoreInst));
 | 
						|
  MemoryAccess *DefiningAccess = LoadAccess->getDefiningAccess();
 | 
						|
  EXPECT_TRUE(isa<MemoryPhi>(DefiningAccess));
 | 
						|
  // The load is currently clobbered by one of the phi arguments, so the walker
 | 
						|
  // should determine the clobbering access as the phi.
 | 
						|
  EXPECT_EQ(DefiningAccess, Walker->getClobberingMemoryAccess(LoadInst));
 | 
						|
  Updater.removeMemoryAccess(StoreAccess);
 | 
						|
  MSSA.verifyMemorySSA();
 | 
						|
  // After the removeaccess, let's see if we got the right accesses
 | 
						|
  // The load should still point to the phi ...
 | 
						|
  EXPECT_EQ(DefiningAccess, LoadAccess->getDefiningAccess());
 | 
						|
  // but we should now get live on entry for the clobbering definition of the
 | 
						|
  // load, since it will walk past the phi node since every argument is the
 | 
						|
  // same.
 | 
						|
  // XXX: This currently requires either removing the phi or resetting optimized
 | 
						|
  // on the load
 | 
						|
 | 
						|
  EXPECT_FALSE(
 | 
						|
      MSSA.isLiveOnEntryDef(Walker->getClobberingMemoryAccess(LoadInst)));
 | 
						|
  // If we reset optimized, we get live on entry.
 | 
						|
  LoadAccess->resetOptimized();
 | 
						|
  EXPECT_TRUE(
 | 
						|
      MSSA.isLiveOnEntryDef(Walker->getClobberingMemoryAccess(LoadInst)));
 | 
						|
  // The phi should now be a two entry phi with two live on entry defs.
 | 
						|
  for (const auto &Op : DefiningAccess->operands()) {
 | 
						|
    MemoryAccess *Operand = cast<MemoryAccess>(&*Op);
 | 
						|
    EXPECT_TRUE(MSSA.isLiveOnEntryDef(Operand));
 | 
						|
  }
 | 
						|
 | 
						|
  // Now we try to remove the single valued phi
 | 
						|
  Updater.removeMemoryAccess(DefiningAccess);
 | 
						|
  MSSA.verifyMemorySSA();
 | 
						|
  // Now the load should be a load of live on entry.
 | 
						|
  EXPECT_TRUE(MSSA.isLiveOnEntryDef(LoadAccess->getDefiningAccess()));
 | 
						|
}
 | 
						|
 | 
						|
// We had a bug with caching where the walker would report MemoryDef#3's clobber
 | 
						|
// (below) was MemoryDef#1.
 | 
						|
//
 | 
						|
// define void @F(i8*) {
 | 
						|
//   %A = alloca i8, i8 1
 | 
						|
// ; 1 = MemoryDef(liveOnEntry)
 | 
						|
//   store i8 0, i8* %A
 | 
						|
// ; 2 = MemoryDef(1)
 | 
						|
//   store i8 1, i8* %A
 | 
						|
// ; 3 = MemoryDef(2)
 | 
						|
//   store i8 2, i8* %A
 | 
						|
// }
 | 
						|
TEST_F(MemorySSATest, TestTripleStore) {
 | 
						|
  F = Function::Create(FunctionType::get(B.getVoidTy(), {}, false),
 | 
						|
                       GlobalValue::ExternalLinkage, "F", &M);
 | 
						|
  B.SetInsertPoint(BasicBlock::Create(C, "", F));
 | 
						|
  Type *Int8 = Type::getInt8Ty(C);
 | 
						|
  Value *Alloca = B.CreateAlloca(Int8, ConstantInt::get(Int8, 1), "A");
 | 
						|
  StoreInst *S1 = B.CreateStore(ConstantInt::get(Int8, 0), Alloca);
 | 
						|
  StoreInst *S2 = B.CreateStore(ConstantInt::get(Int8, 1), Alloca);
 | 
						|
  StoreInst *S3 = B.CreateStore(ConstantInt::get(Int8, 2), Alloca);
 | 
						|
 | 
						|
  setupAnalyses();
 | 
						|
  MemorySSA &MSSA = *Analyses->MSSA;
 | 
						|
  MemorySSAWalker *Walker = Analyses->Walker;
 | 
						|
 | 
						|
  unsigned I = 0;
 | 
						|
  for (StoreInst *V : {S1, S2, S3}) {
 | 
						|
    // Everything should be clobbered by its defining access
 | 
						|
    MemoryAccess *DefiningAccess = MSSA.getMemoryAccess(V)->getDefiningAccess();
 | 
						|
    MemoryAccess *WalkerClobber = Walker->getClobberingMemoryAccess(V);
 | 
						|
    EXPECT_EQ(DefiningAccess, WalkerClobber)
 | 
						|
        << "Store " << I << " doesn't have the correct clobbering access";
 | 
						|
    // EXPECT_EQ expands such that if we increment I above, it won't get
 | 
						|
    // incremented except when we try to print the error message.
 | 
						|
    ++I;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
// ...And fixing the above bug made it obvious that, when walking, MemorySSA's
 | 
						|
// walker was caching the initial node it walked. This was fine (albeit
 | 
						|
// mostly redundant) unless the initial node being walked is a clobber for the
 | 
						|
// query. In that case, we'd cache that the node clobbered itself.
 | 
						|
TEST_F(MemorySSATest, TestStoreAndLoad) {
 | 
						|
  F = Function::Create(FunctionType::get(B.getVoidTy(), {}, false),
 | 
						|
                       GlobalValue::ExternalLinkage, "F", &M);
 | 
						|
  B.SetInsertPoint(BasicBlock::Create(C, "", F));
 | 
						|
  Type *Int8 = Type::getInt8Ty(C);
 | 
						|
  Value *Alloca = B.CreateAlloca(Int8, ConstantInt::get(Int8, 1), "A");
 | 
						|
  Instruction *SI = B.CreateStore(ConstantInt::get(Int8, 0), Alloca);
 | 
						|
  Instruction *LI = B.CreateLoad(Int8, Alloca);
 | 
						|
 | 
						|
  setupAnalyses();
 | 
						|
  MemorySSA &MSSA = *Analyses->MSSA;
 | 
						|
  MemorySSAWalker *Walker = Analyses->Walker;
 | 
						|
 | 
						|
  MemoryAccess *LoadClobber = Walker->getClobberingMemoryAccess(LI);
 | 
						|
  EXPECT_EQ(LoadClobber, MSSA.getMemoryAccess(SI));
 | 
						|
  EXPECT_TRUE(MSSA.isLiveOnEntryDef(Walker->getClobberingMemoryAccess(SI)));
 | 
						|
}
 | 
						|
 | 
						|
// Another bug (related to the above two fixes): It was noted that, given the
 | 
						|
// following code:
 | 
						|
// ; 1 = MemoryDef(liveOnEntry)
 | 
						|
// store i8 0, i8* %1
 | 
						|
//
 | 
						|
// ...A query to getClobberingMemoryAccess(MemoryAccess*, MemoryLocation) would
 | 
						|
// hand back the store (correctly). A later call to
 | 
						|
// getClobberingMemoryAccess(const Instruction*) would also hand back the store
 | 
						|
// (incorrectly; it should return liveOnEntry).
 | 
						|
//
 | 
						|
// This test checks that repeated calls to either function returns what they're
 | 
						|
// meant to.
 | 
						|
TEST_F(MemorySSATest, TestStoreDoubleQuery) {
 | 
						|
  F = Function::Create(FunctionType::get(B.getVoidTy(), {}, false),
 | 
						|
                       GlobalValue::ExternalLinkage, "F", &M);
 | 
						|
  B.SetInsertPoint(BasicBlock::Create(C, "", F));
 | 
						|
  Type *Int8 = Type::getInt8Ty(C);
 | 
						|
  Value *Alloca = B.CreateAlloca(Int8, ConstantInt::get(Int8, 1), "A");
 | 
						|
  StoreInst *SI = B.CreateStore(ConstantInt::get(Int8, 0), Alloca);
 | 
						|
 | 
						|
  setupAnalyses();
 | 
						|
  MemorySSA &MSSA = *Analyses->MSSA;
 | 
						|
  MemorySSAWalker *Walker = Analyses->Walker;
 | 
						|
 | 
						|
  MemoryAccess *StoreAccess = MSSA.getMemoryAccess(SI);
 | 
						|
  MemoryLocation StoreLoc = MemoryLocation::get(SI);
 | 
						|
  MemoryAccess *Clobber =
 | 
						|
      Walker->getClobberingMemoryAccess(StoreAccess, StoreLoc);
 | 
						|
  MemoryAccess *LiveOnEntry = Walker->getClobberingMemoryAccess(SI);
 | 
						|
 | 
						|
  EXPECT_EQ(Clobber, StoreAccess);
 | 
						|
  EXPECT_TRUE(MSSA.isLiveOnEntryDef(LiveOnEntry));
 | 
						|
 | 
						|
  // Try again (with entries in the cache already) for good measure...
 | 
						|
  Clobber = Walker->getClobberingMemoryAccess(StoreAccess, StoreLoc);
 | 
						|
  LiveOnEntry = Walker->getClobberingMemoryAccess(SI);
 | 
						|
  EXPECT_EQ(Clobber, StoreAccess);
 | 
						|
  EXPECT_TRUE(MSSA.isLiveOnEntryDef(LiveOnEntry));
 | 
						|
}
 | 
						|
 | 
						|
// Bug: During phi optimization, the walker wouldn't cache to the proper result
 | 
						|
// in the farthest-walked BB.
 | 
						|
//
 | 
						|
// Specifically, it would assume that whatever we walked to was a clobber.
 | 
						|
// "Whatever we walked to" isn't a clobber if we hit a cache entry.
 | 
						|
//
 | 
						|
// ...So, we need a test case that looks like:
 | 
						|
//    A
 | 
						|
//   / \
 | 
						|
//  B   |
 | 
						|
//   \ /
 | 
						|
//    C
 | 
						|
//
 | 
						|
// Where, when we try to optimize a thing in 'C', a blocker is found in 'B'.
 | 
						|
// The walk must determine that the blocker exists by using cache entries *while
 | 
						|
// walking* 'B'.
 | 
						|
TEST_F(MemorySSATest, PartialWalkerCacheWithPhis) {
 | 
						|
  F = Function::Create(FunctionType::get(B.getVoidTy(), {}, false),
 | 
						|
                       GlobalValue::ExternalLinkage, "F", &M);
 | 
						|
  B.SetInsertPoint(BasicBlock::Create(C, "A", F));
 | 
						|
  Type *Int8 = Type::getInt8Ty(C);
 | 
						|
  Constant *One = ConstantInt::get(Int8, 1);
 | 
						|
  Constant *Zero = ConstantInt::get(Int8, 0);
 | 
						|
  Value *AllocA = B.CreateAlloca(Int8, One, "a");
 | 
						|
  Value *AllocB = B.CreateAlloca(Int8, One, "b");
 | 
						|
  BasicBlock *IfThen = BasicBlock::Create(C, "B", F);
 | 
						|
  BasicBlock *IfEnd = BasicBlock::Create(C, "C", F);
 | 
						|
 | 
						|
  B.CreateCondBr(UndefValue::get(Type::getInt1Ty(C)), IfThen, IfEnd);
 | 
						|
 | 
						|
  B.SetInsertPoint(IfThen);
 | 
						|
  Instruction *FirstStore = B.CreateStore(Zero, AllocA);
 | 
						|
  B.CreateStore(Zero, AllocB);
 | 
						|
  Instruction *ALoad0 = B.CreateLoad(Int8, AllocA, "");
 | 
						|
  Instruction *BStore = B.CreateStore(Zero, AllocB);
 | 
						|
  // Due to use optimization/etc. we make a store to A, which is removed after
 | 
						|
  // we build MSSA. This helps keep the test case simple-ish.
 | 
						|
  Instruction *KillStore = B.CreateStore(Zero, AllocA);
 | 
						|
  Instruction *ALoad = B.CreateLoad(Int8, AllocA, "");
 | 
						|
  B.CreateBr(IfEnd);
 | 
						|
 | 
						|
  B.SetInsertPoint(IfEnd);
 | 
						|
  Instruction *BelowPhi = B.CreateStore(Zero, AllocA);
 | 
						|
 | 
						|
  setupAnalyses();
 | 
						|
  MemorySSA &MSSA = *Analyses->MSSA;
 | 
						|
  MemorySSAWalker *Walker = Analyses->Walker;
 | 
						|
  MemorySSAUpdater Updater(&MSSA);
 | 
						|
 | 
						|
  // Kill `KillStore`; it exists solely so that the load after it won't be
 | 
						|
  // optimized to FirstStore.
 | 
						|
  Updater.removeMemoryAccess(MSSA.getMemoryAccess(KillStore));
 | 
						|
  KillStore->eraseFromParent();
 | 
						|
  auto *ALoadMA = cast<MemoryUse>(MSSA.getMemoryAccess(ALoad));
 | 
						|
  EXPECT_EQ(ALoadMA->getDefiningAccess(), MSSA.getMemoryAccess(BStore));
 | 
						|
 | 
						|
  // Populate the cache for the store to AllocB directly after FirstStore. It
 | 
						|
  // should point to something in block B (so something in D can't be optimized
 | 
						|
  // to it).
 | 
						|
  MemoryAccess *Load0Clobber = Walker->getClobberingMemoryAccess(ALoad0);
 | 
						|
  EXPECT_EQ(MSSA.getMemoryAccess(FirstStore), Load0Clobber);
 | 
						|
 | 
						|
  // If the bug exists, this will introduce a bad cache entry for %a on BStore.
 | 
						|
  // It will point to the store to %b after FirstStore. This only happens during
 | 
						|
  // phi optimization.
 | 
						|
  MemoryAccess *BottomClobber = Walker->getClobberingMemoryAccess(BelowPhi);
 | 
						|
  MemoryAccess *Phi = MSSA.getMemoryAccess(IfEnd);
 | 
						|
  EXPECT_EQ(BottomClobber, Phi);
 | 
						|
 | 
						|
  // This query will first check the cache for {%a, BStore}. It should point to
 | 
						|
  // FirstStore, not to the store after FirstStore.
 | 
						|
  MemoryAccess *UseClobber = Walker->getClobberingMemoryAccess(ALoad);
 | 
						|
  EXPECT_EQ(UseClobber, MSSA.getMemoryAccess(FirstStore));
 | 
						|
}
 | 
						|
 | 
						|
// Test that our walker properly handles loads with the invariant group
 | 
						|
// attribute. It's a bit hacky, since we add the invariant attribute *after*
 | 
						|
// building MSSA. Otherwise, the use optimizer will optimize it for us, which
 | 
						|
// isn't what we want.
 | 
						|
// FIXME: It may be easier/cleaner to just add an 'optimize uses?' flag to MSSA.
 | 
						|
TEST_F(MemorySSATest, WalkerInvariantLoadOpt) {
 | 
						|
  F = Function::Create(FunctionType::get(B.getVoidTy(), {}, false),
 | 
						|
                       GlobalValue::ExternalLinkage, "F", &M);
 | 
						|
  B.SetInsertPoint(BasicBlock::Create(C, "", F));
 | 
						|
  Type *Int8 = Type::getInt8Ty(C);
 | 
						|
  Constant *One = ConstantInt::get(Int8, 1);
 | 
						|
  Value *AllocA = B.CreateAlloca(Int8, One, "");
 | 
						|
 | 
						|
  Instruction *Store = B.CreateStore(One, AllocA);
 | 
						|
  Instruction *Load = B.CreateLoad(Int8, AllocA);
 | 
						|
 | 
						|
  setupAnalyses();
 | 
						|
  MemorySSA &MSSA = *Analyses->MSSA;
 | 
						|
  MemorySSAWalker *Walker = Analyses->Walker;
 | 
						|
 | 
						|
  auto *LoadMA = cast<MemoryUse>(MSSA.getMemoryAccess(Load));
 | 
						|
  auto *StoreMA = cast<MemoryDef>(MSSA.getMemoryAccess(Store));
 | 
						|
  EXPECT_EQ(LoadMA->getDefiningAccess(), StoreMA);
 | 
						|
 | 
						|
  // ...At the time of writing, no cache should exist for LoadMA. Be a bit
 | 
						|
  // flexible to future changes.
 | 
						|
  Walker->invalidateInfo(LoadMA);
 | 
						|
  Load->setMetadata(LLVMContext::MD_invariant_load, MDNode::get(C, {}));
 | 
						|
 | 
						|
  MemoryAccess *LoadClobber = Walker->getClobberingMemoryAccess(LoadMA);
 | 
						|
  EXPECT_EQ(LoadClobber, MSSA.getLiveOnEntryDef());
 | 
						|
}
 | 
						|
 | 
						|
// Test loads get reoptimized properly by the walker.
 | 
						|
TEST_F(MemorySSATest, WalkerReopt) {
 | 
						|
  F = Function::Create(FunctionType::get(B.getVoidTy(), {}, false),
 | 
						|
                       GlobalValue::ExternalLinkage, "F", &M);
 | 
						|
  B.SetInsertPoint(BasicBlock::Create(C, "", F));
 | 
						|
  Type *Int8 = Type::getInt8Ty(C);
 | 
						|
  Value *AllocaA = B.CreateAlloca(Int8, ConstantInt::get(Int8, 1), "A");
 | 
						|
  Instruction *SIA = B.CreateStore(ConstantInt::get(Int8, 0), AllocaA);
 | 
						|
  Value *AllocaB = B.CreateAlloca(Int8, ConstantInt::get(Int8, 1), "B");
 | 
						|
  Instruction *SIB = B.CreateStore(ConstantInt::get(Int8, 0), AllocaB);
 | 
						|
  Instruction *LIA = B.CreateLoad(Int8, AllocaA);
 | 
						|
 | 
						|
  setupAnalyses();
 | 
						|
  MemorySSA &MSSA = *Analyses->MSSA;
 | 
						|
  MemorySSAWalker *Walker = Analyses->Walker;
 | 
						|
  MemorySSAUpdater Updater(&MSSA);
 | 
						|
 | 
						|
  MemoryAccess *LoadClobber = Walker->getClobberingMemoryAccess(LIA);
 | 
						|
  MemoryUse *LoadAccess = cast<MemoryUse>(MSSA.getMemoryAccess(LIA));
 | 
						|
  EXPECT_EQ(LoadClobber, MSSA.getMemoryAccess(SIA));
 | 
						|
  EXPECT_TRUE(MSSA.isLiveOnEntryDef(Walker->getClobberingMemoryAccess(SIA)));
 | 
						|
  Updater.removeMemoryAccess(LoadAccess);
 | 
						|
 | 
						|
  // Create the load memory access pointing to an unoptimized place.
 | 
						|
  MemoryUse *NewLoadAccess = cast<MemoryUse>(Updater.createMemoryAccessInBB(
 | 
						|
      LIA, MSSA.getMemoryAccess(SIB), LIA->getParent(), MemorySSA::End));
 | 
						|
  // This should it cause it to be optimized
 | 
						|
  EXPECT_EQ(Walker->getClobberingMemoryAccess(NewLoadAccess), LoadClobber);
 | 
						|
  EXPECT_EQ(NewLoadAccess->getDefiningAccess(), LoadClobber);
 | 
						|
}
 | 
						|
 | 
						|
// Test out MemorySSAUpdater::moveBefore
 | 
						|
TEST_F(MemorySSATest, MoveAboveMemoryDef) {
 | 
						|
  F = Function::Create(FunctionType::get(B.getVoidTy(), {}, false),
 | 
						|
                       GlobalValue::ExternalLinkage, "F", &M);
 | 
						|
  B.SetInsertPoint(BasicBlock::Create(C, "", F));
 | 
						|
 | 
						|
  Type *Int8 = Type::getInt8Ty(C);
 | 
						|
  Value *A = B.CreateAlloca(Int8, ConstantInt::get(Int8, 1), "A");
 | 
						|
  Value *B_ = B.CreateAlloca(Int8, ConstantInt::get(Int8, 1), "B");
 | 
						|
  Value *C = B.CreateAlloca(Int8, ConstantInt::get(Int8, 1), "C");
 | 
						|
 | 
						|
  StoreInst *StoreA0 = B.CreateStore(ConstantInt::get(Int8, 0), A);
 | 
						|
  StoreInst *StoreB = B.CreateStore(ConstantInt::get(Int8, 0), B_);
 | 
						|
  LoadInst *LoadB = B.CreateLoad(Int8, B_);
 | 
						|
  StoreInst *StoreA1 = B.CreateStore(ConstantInt::get(Int8, 4), A);
 | 
						|
  StoreInst *StoreC = B.CreateStore(ConstantInt::get(Int8, 4), C);
 | 
						|
  StoreInst *StoreA2 = B.CreateStore(ConstantInt::get(Int8, 4), A);
 | 
						|
  LoadInst *LoadC = B.CreateLoad(Int8, C);
 | 
						|
 | 
						|
  setupAnalyses();
 | 
						|
  MemorySSA &MSSA = *Analyses->MSSA;
 | 
						|
  MemorySSAWalker &Walker = *Analyses->Walker;
 | 
						|
 | 
						|
  MemorySSAUpdater Updater(&MSSA);
 | 
						|
  StoreC->moveBefore(StoreB);
 | 
						|
  Updater.moveBefore(cast<MemoryDef>(MSSA.getMemoryAccess(StoreC)),
 | 
						|
                     cast<MemoryDef>(MSSA.getMemoryAccess(StoreB)));
 | 
						|
 | 
						|
  MSSA.verifyMemorySSA();
 | 
						|
 | 
						|
  EXPECT_EQ(MSSA.getMemoryAccess(StoreB)->getDefiningAccess(),
 | 
						|
            MSSA.getMemoryAccess(StoreC));
 | 
						|
  EXPECT_EQ(MSSA.getMemoryAccess(StoreC)->getDefiningAccess(),
 | 
						|
            MSSA.getMemoryAccess(StoreA0));
 | 
						|
  EXPECT_EQ(MSSA.getMemoryAccess(StoreA2)->getDefiningAccess(),
 | 
						|
            MSSA.getMemoryAccess(StoreA1));
 | 
						|
  EXPECT_EQ(Walker.getClobberingMemoryAccess(LoadB),
 | 
						|
            MSSA.getMemoryAccess(StoreB));
 | 
						|
  EXPECT_EQ(Walker.getClobberingMemoryAccess(LoadC),
 | 
						|
            MSSA.getMemoryAccess(StoreC));
 | 
						|
 | 
						|
  // exercise block numbering
 | 
						|
  EXPECT_TRUE(MSSA.locallyDominates(MSSA.getMemoryAccess(StoreC),
 | 
						|
                                    MSSA.getMemoryAccess(StoreB)));
 | 
						|
  EXPECT_TRUE(MSSA.locallyDominates(MSSA.getMemoryAccess(StoreA1),
 | 
						|
                                    MSSA.getMemoryAccess(StoreA2)));
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(MemorySSATest, Irreducible) {
 | 
						|
  // Create the equivalent of
 | 
						|
  // x = something
 | 
						|
  // if (...)
 | 
						|
  //    goto second_loop_entry
 | 
						|
  // while (...) {
 | 
						|
  // second_loop_entry:
 | 
						|
  // }
 | 
						|
  // use(x)
 | 
						|
 | 
						|
  SmallVector<PHINode *, 8> Inserted;
 | 
						|
  IRBuilder<> B(C);
 | 
						|
  F = Function::Create(
 | 
						|
      FunctionType::get(B.getVoidTy(), {B.getInt8PtrTy()}, false),
 | 
						|
      GlobalValue::ExternalLinkage, "F", &M);
 | 
						|
 | 
						|
  // Make blocks
 | 
						|
  BasicBlock *IfBB = BasicBlock::Create(C, "if", F);
 | 
						|
  BasicBlock *LoopStartBB = BasicBlock::Create(C, "loopstart", F);
 | 
						|
  BasicBlock *LoopMainBB = BasicBlock::Create(C, "loopmain", F);
 | 
						|
  BasicBlock *AfterLoopBB = BasicBlock::Create(C, "afterloop", F);
 | 
						|
  B.SetInsertPoint(IfBB);
 | 
						|
  B.CreateCondBr(B.getTrue(), LoopMainBB, LoopStartBB);
 | 
						|
  B.SetInsertPoint(LoopStartBB);
 | 
						|
  B.CreateBr(LoopMainBB);
 | 
						|
  B.SetInsertPoint(LoopMainBB);
 | 
						|
  B.CreateCondBr(B.getTrue(), LoopStartBB, AfterLoopBB);
 | 
						|
  B.SetInsertPoint(AfterLoopBB);
 | 
						|
  Argument *FirstArg = &*F->arg_begin();
 | 
						|
  setupAnalyses();
 | 
						|
  MemorySSA &MSSA = *Analyses->MSSA;
 | 
						|
  MemorySSAUpdater Updater(&MSSA);
 | 
						|
  // Create the load memory acccess
 | 
						|
  LoadInst *LoadInst = B.CreateLoad(B.getInt8Ty(), FirstArg);
 | 
						|
  MemoryUse *LoadAccess = cast<MemoryUse>(Updater.createMemoryAccessInBB(
 | 
						|
      LoadInst, nullptr, AfterLoopBB, MemorySSA::Beginning));
 | 
						|
  Updater.insertUse(LoadAccess);
 | 
						|
  MSSA.verifyMemorySSA();
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(MemorySSATest, MoveToBeforeLiveOnEntryInvalidatesCache) {
 | 
						|
  // Create:
 | 
						|
  //   %1 = alloca i8
 | 
						|
  //   ; 1 = MemoryDef(liveOnEntry)
 | 
						|
  //   store i8 0, i8* %1
 | 
						|
  //   ; 2 = MemoryDef(1)
 | 
						|
  //   store i8 0, i8* %1
 | 
						|
  //
 | 
						|
  // ...And be sure that MSSA's caching doesn't give us `1` for the clobber of
 | 
						|
  // `2` after `1` is removed.
 | 
						|
  IRBuilder<> B(C);
 | 
						|
  F = Function::Create(
 | 
						|
      FunctionType::get(B.getVoidTy(), {B.getInt8PtrTy()}, false),
 | 
						|
      GlobalValue::ExternalLinkage, "F", &M);
 | 
						|
 | 
						|
  BasicBlock *Entry = BasicBlock::Create(C, "if", F);
 | 
						|
  B.SetInsertPoint(Entry);
 | 
						|
 | 
						|
  Value *A = B.CreateAlloca(B.getInt8Ty());
 | 
						|
  StoreInst *StoreA = B.CreateStore(B.getInt8(0), A);
 | 
						|
  StoreInst *StoreB = B.CreateStore(B.getInt8(0), A);
 | 
						|
 | 
						|
  setupAnalyses();
 | 
						|
 | 
						|
  MemorySSA &MSSA = *Analyses->MSSA;
 | 
						|
 | 
						|
  auto *DefA = cast<MemoryDef>(MSSA.getMemoryAccess(StoreA));
 | 
						|
  auto *DefB = cast<MemoryDef>(MSSA.getMemoryAccess(StoreB));
 | 
						|
 | 
						|
  MemoryAccess *BClobber = MSSA.getWalker()->getClobberingMemoryAccess(DefB);
 | 
						|
  ASSERT_EQ(DefA, BClobber);
 | 
						|
 | 
						|
  MemorySSAUpdater(&MSSA).removeMemoryAccess(DefA);
 | 
						|
  StoreA->eraseFromParent();
 | 
						|
 | 
						|
  EXPECT_EQ(DefB->getDefiningAccess(), MSSA.getLiveOnEntryDef());
 | 
						|
 | 
						|
  EXPECT_EQ(MSSA.getWalker()->getClobberingMemoryAccess(DefB),
 | 
						|
            MSSA.getLiveOnEntryDef())
 | 
						|
      << "(DefA = " << DefA << ")";
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(MemorySSATest, RemovingDefInvalidatesCache) {
 | 
						|
  // Create:
 | 
						|
  //   %x = alloca i8
 | 
						|
  //   %y = alloca i8
 | 
						|
  //   ; 1 = MemoryDef(liveOnEntry)
 | 
						|
  //   store i8 0, i8* %x
 | 
						|
  //   ; 2 = MemoryDef(1)
 | 
						|
  //   store i8 0, i8* %y
 | 
						|
  //   ; 3 = MemoryDef(2)
 | 
						|
  //   store i8 0, i8* %x
 | 
						|
  //
 | 
						|
  // And be sure that MSSA's caching handles the removal of def `1`
 | 
						|
  // appropriately.
 | 
						|
  IRBuilder<> B(C);
 | 
						|
  F = Function::Create(
 | 
						|
      FunctionType::get(B.getVoidTy(), {B.getInt8PtrTy()}, false),
 | 
						|
      GlobalValue::ExternalLinkage, "F", &M);
 | 
						|
 | 
						|
  BasicBlock *Entry = BasicBlock::Create(C, "if", F);
 | 
						|
  B.SetInsertPoint(Entry);
 | 
						|
 | 
						|
  Value *X = B.CreateAlloca(B.getInt8Ty());
 | 
						|
  Value *Y = B.CreateAlloca(B.getInt8Ty());
 | 
						|
  StoreInst *StoreX1 = B.CreateStore(B.getInt8(0), X);
 | 
						|
  StoreInst *StoreY = B.CreateStore(B.getInt8(0), Y);
 | 
						|
  StoreInst *StoreX2 = B.CreateStore(B.getInt8(0), X);
 | 
						|
 | 
						|
  setupAnalyses();
 | 
						|
 | 
						|
  MemorySSA &MSSA = *Analyses->MSSA;
 | 
						|
 | 
						|
  auto *DefX1 = cast<MemoryDef>(MSSA.getMemoryAccess(StoreX1));
 | 
						|
  auto *DefY = cast<MemoryDef>(MSSA.getMemoryAccess(StoreY));
 | 
						|
  auto *DefX2 = cast<MemoryDef>(MSSA.getMemoryAccess(StoreX2));
 | 
						|
 | 
						|
  EXPECT_EQ(DefX2->getDefiningAccess(), DefY);
 | 
						|
  MemoryAccess *X2Clobber = MSSA.getWalker()->getClobberingMemoryAccess(DefX2);
 | 
						|
  ASSERT_EQ(DefX1, X2Clobber);
 | 
						|
 | 
						|
  MemorySSAUpdater(&MSSA).removeMemoryAccess(DefX1);
 | 
						|
  StoreX1->eraseFromParent();
 | 
						|
 | 
						|
  EXPECT_EQ(DefX2->getDefiningAccess(), DefY);
 | 
						|
  EXPECT_EQ(MSSA.getWalker()->getClobberingMemoryAccess(DefX2),
 | 
						|
            MSSA.getLiveOnEntryDef())
 | 
						|
      << "(DefX1 = " << DefX1 << ")";
 | 
						|
}
 | 
						|
 | 
						|
// Test Must alias for optimized uses
 | 
						|
TEST_F(MemorySSATest, TestLoadMustAlias) {
 | 
						|
  F = Function::Create(FunctionType::get(B.getVoidTy(), {}, false),
 | 
						|
                       GlobalValue::ExternalLinkage, "F", &M);
 | 
						|
  B.SetInsertPoint(BasicBlock::Create(C, "", F));
 | 
						|
  Type *Int8 = Type::getInt8Ty(C);
 | 
						|
  Value *AllocaA = B.CreateAlloca(Int8, ConstantInt::get(Int8, 1), "A");
 | 
						|
  Value *AllocaB = B.CreateAlloca(Int8, ConstantInt::get(Int8, 1), "B");
 | 
						|
 | 
						|
  B.CreateStore(ConstantInt::get(Int8, 1), AllocaB);
 | 
						|
  // Check load from LOE
 | 
						|
  LoadInst *LA1 = B.CreateLoad(Int8, AllocaA, "");
 | 
						|
  // Check load alias cached for second load
 | 
						|
  LoadInst *LA2 = B.CreateLoad(Int8, AllocaA, "");
 | 
						|
 | 
						|
  B.CreateStore(ConstantInt::get(Int8, 1), AllocaA);
 | 
						|
  // Check load from store/def
 | 
						|
  LoadInst *LA3 = B.CreateLoad(Int8, AllocaA, "");
 | 
						|
  // Check load alias cached for second load
 | 
						|
  LoadInst *LA4 = B.CreateLoad(Int8, AllocaA, "");
 | 
						|
 | 
						|
  setupAnalyses();
 | 
						|
  MemorySSA &MSSA = *Analyses->MSSA;
 | 
						|
 | 
						|
  unsigned I = 0;
 | 
						|
  for (LoadInst *V : {LA1, LA2}) {
 | 
						|
    MemoryUse *MemUse = dyn_cast_or_null<MemoryUse>(MSSA.getMemoryAccess(V));
 | 
						|
    EXPECT_EQ(MemUse->getOptimizedAccessType(), None)
 | 
						|
        << "Load " << I << " doesn't have the correct alias information";
 | 
						|
    // EXPECT_EQ expands such that if we increment I above, it won't get
 | 
						|
    // incremented except when we try to print the error message.
 | 
						|
    ++I;
 | 
						|
  }
 | 
						|
  for (LoadInst *V : {LA3, LA4}) {
 | 
						|
    MemoryUse *MemUse = dyn_cast_or_null<MemoryUse>(MSSA.getMemoryAccess(V));
 | 
						|
    EXPECT_EQ(MemUse->getOptimizedAccessType(), MustAlias)
 | 
						|
        << "Load " << I << " doesn't have the correct alias information";
 | 
						|
    // EXPECT_EQ expands such that if we increment I above, it won't get
 | 
						|
    // incremented except when we try to print the error message.
 | 
						|
    ++I;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
// Test Must alias for optimized defs.
 | 
						|
TEST_F(MemorySSATest, TestStoreMustAlias) {
 | 
						|
  F = Function::Create(FunctionType::get(B.getVoidTy(), {}, false),
 | 
						|
                       GlobalValue::ExternalLinkage, "F", &M);
 | 
						|
  B.SetInsertPoint(BasicBlock::Create(C, "", F));
 | 
						|
  Type *Int8 = Type::getInt8Ty(C);
 | 
						|
  Value *AllocaA = B.CreateAlloca(Int8, ConstantInt::get(Int8, 1), "A");
 | 
						|
  Value *AllocaB = B.CreateAlloca(Int8, ConstantInt::get(Int8, 1), "B");
 | 
						|
  StoreInst *SA1 = B.CreateStore(ConstantInt::get(Int8, 1), AllocaA);
 | 
						|
  StoreInst *SB1 = B.CreateStore(ConstantInt::get(Int8, 1), AllocaB);
 | 
						|
  StoreInst *SA2 = B.CreateStore(ConstantInt::get(Int8, 2), AllocaA);
 | 
						|
  StoreInst *SB2 = B.CreateStore(ConstantInt::get(Int8, 2), AllocaB);
 | 
						|
  StoreInst *SA3 = B.CreateStore(ConstantInt::get(Int8, 3), AllocaA);
 | 
						|
  StoreInst *SB3 = B.CreateStore(ConstantInt::get(Int8, 3), AllocaB);
 | 
						|
 | 
						|
  setupAnalyses();
 | 
						|
  MemorySSA &MSSA = *Analyses->MSSA;
 | 
						|
  MemorySSAWalker *Walker = Analyses->Walker;
 | 
						|
 | 
						|
  unsigned I = 0;
 | 
						|
  for (StoreInst *V : {SA1, SB1, SA2, SB2, SA3, SB3}) {
 | 
						|
    MemoryDef *MemDef = dyn_cast_or_null<MemoryDef>(MSSA.getMemoryAccess(V));
 | 
						|
    EXPECT_EQ(MemDef->isOptimized(), false)
 | 
						|
        << "Store " << I << " is optimized from the start?";
 | 
						|
    EXPECT_EQ(MemDef->getOptimizedAccessType(), MayAlias)
 | 
						|
        << "Store " << I
 | 
						|
        << " has correct alias information before being optimized?";
 | 
						|
    if (V == SA1)
 | 
						|
      Walker->getClobberingMemoryAccess(V);
 | 
						|
    else {
 | 
						|
      MemoryAccess *Def = MemDef->getDefiningAccess();
 | 
						|
      MemoryAccess *Clob = Walker->getClobberingMemoryAccess(V);
 | 
						|
      EXPECT_NE(Def, Clob) << "Store " << I
 | 
						|
                           << " has Defining Access equal to Clobbering Access";
 | 
						|
    }
 | 
						|
    EXPECT_EQ(MemDef->isOptimized(), true)
 | 
						|
        << "Store " << I << " was not optimized";
 | 
						|
    if (I == 0 || I == 1)
 | 
						|
      EXPECT_EQ(MemDef->getOptimizedAccessType(), None)
 | 
						|
          << "Store " << I << " doesn't have the correct alias information";
 | 
						|
    else
 | 
						|
      EXPECT_EQ(MemDef->getOptimizedAccessType(), MustAlias)
 | 
						|
          << "Store " << I << " doesn't have the correct alias information";
 | 
						|
    // EXPECT_EQ expands such that if we increment I above, it won't get
 | 
						|
    // incremented except when we try to print the error message.
 | 
						|
    ++I;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
// Test May alias for optimized uses.
 | 
						|
TEST_F(MemorySSATest, TestLoadMayAlias) {
 | 
						|
  F = Function::Create(FunctionType::get(B.getVoidTy(),
 | 
						|
                                         {B.getInt8PtrTy(), B.getInt8PtrTy()},
 | 
						|
                                         false),
 | 
						|
                       GlobalValue::ExternalLinkage, "F", &M);
 | 
						|
  B.SetInsertPoint(BasicBlock::Create(C, "", F));
 | 
						|
  Type *Int8 = Type::getInt8Ty(C);
 | 
						|
  auto *ArgIt = F->arg_begin();
 | 
						|
  Argument *PointerA = &*ArgIt;
 | 
						|
  Argument *PointerB = &*(++ArgIt);
 | 
						|
  B.CreateStore(ConstantInt::get(Int8, 1), PointerB);
 | 
						|
  LoadInst *LA1 = B.CreateLoad(Int8, PointerA, "");
 | 
						|
  B.CreateStore(ConstantInt::get(Int8, 0), PointerA);
 | 
						|
  LoadInst *LB1 = B.CreateLoad(Int8, PointerB, "");
 | 
						|
  B.CreateStore(ConstantInt::get(Int8, 0), PointerA);
 | 
						|
  LoadInst *LA2 = B.CreateLoad(Int8, PointerA, "");
 | 
						|
  B.CreateStore(ConstantInt::get(Int8, 0), PointerB);
 | 
						|
  LoadInst *LB2 = B.CreateLoad(Int8, PointerB, "");
 | 
						|
 | 
						|
  setupAnalyses();
 | 
						|
  MemorySSA &MSSA = *Analyses->MSSA;
 | 
						|
 | 
						|
  unsigned I = 0;
 | 
						|
  for (LoadInst *V : {LA1, LB1}) {
 | 
						|
    MemoryUse *MemUse = dyn_cast_or_null<MemoryUse>(MSSA.getMemoryAccess(V));
 | 
						|
    EXPECT_EQ(MemUse->getOptimizedAccessType(), MayAlias)
 | 
						|
        << "Load " << I << " doesn't have the correct alias information";
 | 
						|
    // EXPECT_EQ expands such that if we increment I above, it won't get
 | 
						|
    // incremented except when we try to print the error message.
 | 
						|
    ++I;
 | 
						|
  }
 | 
						|
  for (LoadInst *V : {LA2, LB2}) {
 | 
						|
    MemoryUse *MemUse = dyn_cast_or_null<MemoryUse>(MSSA.getMemoryAccess(V));
 | 
						|
    EXPECT_EQ(MemUse->getOptimizedAccessType(), MustAlias)
 | 
						|
        << "Load " << I << " doesn't have the correct alias information";
 | 
						|
    // EXPECT_EQ expands such that if we increment I above, it won't get
 | 
						|
    // incremented except when we try to print the error message.
 | 
						|
    ++I;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
// Test May alias for optimized defs.
 | 
						|
TEST_F(MemorySSATest, TestStoreMayAlias) {
 | 
						|
  F = Function::Create(FunctionType::get(B.getVoidTy(),
 | 
						|
                                         {B.getInt8PtrTy(), B.getInt8PtrTy()},
 | 
						|
                                         false),
 | 
						|
                       GlobalValue::ExternalLinkage, "F", &M);
 | 
						|
  B.SetInsertPoint(BasicBlock::Create(C, "", F));
 | 
						|
  Type *Int8 = Type::getInt8Ty(C);
 | 
						|
  auto *ArgIt = F->arg_begin();
 | 
						|
  Argument *PointerA = &*ArgIt;
 | 
						|
  Argument *PointerB = &*(++ArgIt);
 | 
						|
  Value *AllocaC = B.CreateAlloca(Int8, ConstantInt::get(Int8, 1), "C");
 | 
						|
  // Store into arg1, must alias because it's LOE => must
 | 
						|
  StoreInst *SA1 = B.CreateStore(ConstantInt::get(Int8, 0), PointerA);
 | 
						|
  // Store into arg2, may alias store to arg1 => may
 | 
						|
  StoreInst *SB1 = B.CreateStore(ConstantInt::get(Int8, 1), PointerB);
 | 
						|
  // Store into aloca, no alias with args, so must alias LOE => must
 | 
						|
  StoreInst *SC1 = B.CreateStore(ConstantInt::get(Int8, 2), AllocaC);
 | 
						|
  // Store into arg1, may alias store to arg2 => may
 | 
						|
  StoreInst *SA2 = B.CreateStore(ConstantInt::get(Int8, 3), PointerA);
 | 
						|
  // Store into arg2, may alias store to arg1 => may
 | 
						|
  StoreInst *SB2 = B.CreateStore(ConstantInt::get(Int8, 4), PointerB);
 | 
						|
  // Store into aloca, no alias with args, so must alias SC1 => must
 | 
						|
  StoreInst *SC2 = B.CreateStore(ConstantInt::get(Int8, 5), AllocaC);
 | 
						|
  // Store into arg2, must alias store to arg2 => must
 | 
						|
  StoreInst *SB3 = B.CreateStore(ConstantInt::get(Int8, 6), PointerB);
 | 
						|
  std::initializer_list<StoreInst *> Sts = {SA1, SB1, SC1, SA2, SB2, SC2, SB3};
 | 
						|
 | 
						|
  setupAnalyses();
 | 
						|
  MemorySSA &MSSA = *Analyses->MSSA;
 | 
						|
  MemorySSAWalker *Walker = Analyses->Walker;
 | 
						|
 | 
						|
  unsigned I = 0;
 | 
						|
  for (StoreInst *V : Sts) {
 | 
						|
    MemoryDef *MemDef = dyn_cast_or_null<MemoryDef>(MSSA.getMemoryAccess(V));
 | 
						|
    EXPECT_EQ(MemDef->isOptimized(), false)
 | 
						|
        << "Store " << I << " is optimized from the start?";
 | 
						|
    EXPECT_EQ(MemDef->getOptimizedAccessType(), MayAlias)
 | 
						|
        << "Store " << I
 | 
						|
        << " has correct alias information before being optimized?";
 | 
						|
    ++I;
 | 
						|
  }
 | 
						|
 | 
						|
  for (StoreInst *V : Sts)
 | 
						|
    Walker->getClobberingMemoryAccess(V);
 | 
						|
 | 
						|
  I = 0;
 | 
						|
  for (StoreInst *V : Sts) {
 | 
						|
    MemoryDef *MemDef = dyn_cast_or_null<MemoryDef>(MSSA.getMemoryAccess(V));
 | 
						|
    EXPECT_EQ(MemDef->isOptimized(), true)
 | 
						|
        << "Store " << I << " was not optimized";
 | 
						|
    if (I == 1 || I == 3 || I == 4)
 | 
						|
      EXPECT_EQ(MemDef->getOptimizedAccessType(), MayAlias)
 | 
						|
          << "Store " << I << " doesn't have the correct alias information";
 | 
						|
    else if (I == 0 || I == 2)
 | 
						|
      EXPECT_EQ(MemDef->getOptimizedAccessType(), None)
 | 
						|
          << "Store " << I << " doesn't have the correct alias information";
 | 
						|
    else
 | 
						|
      EXPECT_EQ(MemDef->getOptimizedAccessType(), MustAlias)
 | 
						|
          << "Store " << I << " doesn't have the correct alias information";
 | 
						|
    // EXPECT_EQ expands such that if we increment I above, it won't get
 | 
						|
    // incremented except when we try to print the error message.
 | 
						|
    ++I;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(MemorySSATest, LifetimeMarkersAreClobbers) {
 | 
						|
  // Example code:
 | 
						|
  // define void @a(i8* %foo) {
 | 
						|
  //   %bar = getelementptr i8, i8* %foo, i64 1
 | 
						|
  //   store i8 0, i8* %foo
 | 
						|
  //   store i8 0, i8* %bar
 | 
						|
  //   call void @llvm.lifetime.end.p0i8(i64 8, i32* %p)
 | 
						|
  //   call void @llvm.lifetime.start.p0i8(i64 8, i32* %p)
 | 
						|
  //   store i8 0, i8* %foo
 | 
						|
  //   store i8 0, i8* %bar
 | 
						|
  //   ret void
 | 
						|
  // }
 | 
						|
  //
 | 
						|
  // Patterns like this are possible after inlining; the stores to %foo and %bar
 | 
						|
  // should both be clobbered by the lifetime.start call if they're dominated by
 | 
						|
  // it.
 | 
						|
 | 
						|
  IRBuilder<> B(C);
 | 
						|
  F = Function::Create(
 | 
						|
      FunctionType::get(B.getVoidTy(), {B.getInt8PtrTy()}, false),
 | 
						|
      GlobalValue::ExternalLinkage, "F", &M);
 | 
						|
 | 
						|
  // Make blocks
 | 
						|
  BasicBlock *Entry = BasicBlock::Create(C, "entry", F);
 | 
						|
 | 
						|
  B.SetInsertPoint(Entry);
 | 
						|
  Value *Foo = &*F->arg_begin();
 | 
						|
 | 
						|
  Value *Bar = B.CreateGEP(B.getInt8Ty(), Foo, B.getInt64(1), "bar");
 | 
						|
 | 
						|
  B.CreateStore(B.getInt8(0), Foo);
 | 
						|
  B.CreateStore(B.getInt8(0), Bar);
 | 
						|
 | 
						|
  auto GetLifetimeIntrinsic = [&](Intrinsic::ID ID) {
 | 
						|
    return Intrinsic::getDeclaration(&M, ID, {Foo->getType()});
 | 
						|
  };
 | 
						|
 | 
						|
  B.CreateCall(GetLifetimeIntrinsic(Intrinsic::lifetime_end),
 | 
						|
               {B.getInt64(2), Foo});
 | 
						|
  Instruction *LifetimeStart = B.CreateCall(
 | 
						|
      GetLifetimeIntrinsic(Intrinsic::lifetime_start), {B.getInt64(2), Foo});
 | 
						|
 | 
						|
  Instruction *FooStore = B.CreateStore(B.getInt8(0), Foo);
 | 
						|
  Instruction *BarStore = B.CreateStore(B.getInt8(0), Bar);
 | 
						|
 | 
						|
  setupAnalyses();
 | 
						|
  MemorySSA &MSSA = *Analyses->MSSA;
 | 
						|
 | 
						|
  MemoryAccess *LifetimeStartAccess = MSSA.getMemoryAccess(LifetimeStart);
 | 
						|
  ASSERT_NE(LifetimeStartAccess, nullptr);
 | 
						|
 | 
						|
  MemoryAccess *FooAccess = MSSA.getMemoryAccess(FooStore);
 | 
						|
  ASSERT_NE(FooAccess, nullptr);
 | 
						|
 | 
						|
  MemoryAccess *BarAccess = MSSA.getMemoryAccess(BarStore);
 | 
						|
  ASSERT_NE(BarAccess, nullptr);
 | 
						|
 | 
						|
  MemoryAccess *FooClobber =
 | 
						|
      MSSA.getWalker()->getClobberingMemoryAccess(FooAccess);
 | 
						|
  EXPECT_EQ(FooClobber, LifetimeStartAccess);
 | 
						|
 | 
						|
  MemoryAccess *BarClobber =
 | 
						|
      MSSA.getWalker()->getClobberingMemoryAccess(BarAccess);
 | 
						|
  EXPECT_EQ(BarClobber, LifetimeStartAccess);
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(MemorySSATest, DefOptimizationsAreInvalidatedOnMoving) {
 | 
						|
  IRBuilder<> B(C);
 | 
						|
  F = Function::Create(FunctionType::get(B.getVoidTy(), {B.getInt1Ty()}, false),
 | 
						|
                       GlobalValue::ExternalLinkage, "F", &M);
 | 
						|
 | 
						|
  // Make a CFG like
 | 
						|
  //     entry
 | 
						|
  //      / \
 | 
						|
  //     a   b
 | 
						|
  //      \ /
 | 
						|
  //       c
 | 
						|
  //
 | 
						|
  // Put a def in A and a def in B, move the def from A -> B, observe as the
 | 
						|
  // optimization is invalidated.
 | 
						|
  BasicBlock *Entry = BasicBlock::Create(C, "entry", F);
 | 
						|
  BasicBlock *BlockA = BasicBlock::Create(C, "a", F);
 | 
						|
  BasicBlock *BlockB = BasicBlock::Create(C, "b", F);
 | 
						|
  BasicBlock *BlockC = BasicBlock::Create(C, "c", F);
 | 
						|
 | 
						|
  B.SetInsertPoint(Entry);
 | 
						|
  Type *Int8 = Type::getInt8Ty(C);
 | 
						|
  Value *Alloca = B.CreateAlloca(Int8, ConstantInt::get(Int8, 1), "alloc");
 | 
						|
  StoreInst *StoreEntry = B.CreateStore(B.getInt8(0), Alloca);
 | 
						|
  B.CreateCondBr(B.getTrue(), BlockA, BlockB);
 | 
						|
 | 
						|
  B.SetInsertPoint(BlockA);
 | 
						|
  StoreInst *StoreA = B.CreateStore(B.getInt8(1), Alloca);
 | 
						|
  B.CreateBr(BlockC);
 | 
						|
 | 
						|
  B.SetInsertPoint(BlockB);
 | 
						|
  StoreInst *StoreB = B.CreateStore(B.getInt8(2), Alloca);
 | 
						|
  B.CreateBr(BlockC);
 | 
						|
 | 
						|
  B.SetInsertPoint(BlockC);
 | 
						|
  B.CreateUnreachable();
 | 
						|
 | 
						|
  setupAnalyses();
 | 
						|
  MemorySSA &MSSA = *Analyses->MSSA;
 | 
						|
 | 
						|
  auto *AccessEntry = cast<MemoryDef>(MSSA.getMemoryAccess(StoreEntry));
 | 
						|
  auto *StoreAEntry = cast<MemoryDef>(MSSA.getMemoryAccess(StoreA));
 | 
						|
  auto *StoreBEntry = cast<MemoryDef>(MSSA.getMemoryAccess(StoreB));
 | 
						|
 | 
						|
  ASSERT_EQ(MSSA.getWalker()->getClobberingMemoryAccess(StoreAEntry),
 | 
						|
            AccessEntry);
 | 
						|
  ASSERT_TRUE(StoreAEntry->isOptimized());
 | 
						|
 | 
						|
  ASSERT_EQ(MSSA.getWalker()->getClobberingMemoryAccess(StoreBEntry),
 | 
						|
            AccessEntry);
 | 
						|
  ASSERT_TRUE(StoreBEntry->isOptimized());
 | 
						|
 | 
						|
  // Note that if we did InsertionPlace::Beginning, we don't go out of our way
 | 
						|
  // to invalidate the cache for StoreBEntry. If the user wants to actually do
 | 
						|
  // moves like these, it's up to them to ensure that nearby cache entries are
 | 
						|
  // correctly invalidated (which, in general, requires walking all instructions
 | 
						|
  // that the moved instruction dominates. So we probably shouldn't be doing
 | 
						|
  // moves like this in general. Still, works as a test-case. ;) )
 | 
						|
  MemorySSAUpdater(&MSSA).moveToPlace(StoreAEntry, BlockB,
 | 
						|
                                      MemorySSA::InsertionPlace::End);
 | 
						|
  ASSERT_FALSE(StoreAEntry->isOptimized());
 | 
						|
  ASSERT_EQ(MSSA.getWalker()->getClobberingMemoryAccess(StoreAEntry),
 | 
						|
            StoreBEntry);
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(MemorySSATest, TestOptimizedDefsAreProperUses) {
 | 
						|
  F = Function::Create(FunctionType::get(B.getVoidTy(),
 | 
						|
                                         {B.getInt8PtrTy(), B.getInt8PtrTy()},
 | 
						|
                                         false),
 | 
						|
                       GlobalValue::ExternalLinkage, "F", &M);
 | 
						|
  B.SetInsertPoint(BasicBlock::Create(C, "", F));
 | 
						|
  Type *Int8 = Type::getInt8Ty(C);
 | 
						|
  Value *AllocA = B.CreateAlloca(Int8, ConstantInt::get(Int8, 1), "A");
 | 
						|
  Value *AllocB = B.CreateAlloca(Int8, ConstantInt::get(Int8, 1), "B");
 | 
						|
 | 
						|
  StoreInst *StoreA = B.CreateStore(ConstantInt::get(Int8, 0), AllocA);
 | 
						|
  StoreInst *StoreB = B.CreateStore(ConstantInt::get(Int8, 1), AllocB);
 | 
						|
  StoreInst *StoreA2 = B.CreateStore(ConstantInt::get(Int8, 2), AllocA);
 | 
						|
 | 
						|
  setupAnalyses();
 | 
						|
  MemorySSA &MSSA = *Analyses->MSSA;
 | 
						|
  MemorySSAWalker *Walker = Analyses->Walker;
 | 
						|
 | 
						|
  // If these don't hold, there's no chance of the test result being useful.
 | 
						|
  ASSERT_EQ(Walker->getClobberingMemoryAccess(StoreA),
 | 
						|
            MSSA.getLiveOnEntryDef());
 | 
						|
  ASSERT_EQ(Walker->getClobberingMemoryAccess(StoreB),
 | 
						|
            MSSA.getLiveOnEntryDef());
 | 
						|
  auto *StoreAAccess = cast<MemoryDef>(MSSA.getMemoryAccess(StoreA));
 | 
						|
  auto *StoreA2Access = cast<MemoryDef>(MSSA.getMemoryAccess(StoreA2));
 | 
						|
  ASSERT_EQ(Walker->getClobberingMemoryAccess(StoreA2), StoreAAccess);
 | 
						|
  ASSERT_EQ(StoreA2Access->getOptimized(), StoreAAccess);
 | 
						|
 | 
						|
  auto *StoreBAccess = cast<MemoryDef>(MSSA.getMemoryAccess(StoreB));
 | 
						|
  ASSERT_LT(StoreAAccess->getID(), StoreBAccess->getID());
 | 
						|
  ASSERT_LT(StoreBAccess->getID(), StoreA2Access->getID());
 | 
						|
 | 
						|
  auto SortVecByID = [](std::vector<const MemoryDef *> &Defs) {
 | 
						|
    llvm::sort(Defs, [](const MemoryDef *LHS, const MemoryDef *RHS) {
 | 
						|
      return LHS->getID() < RHS->getID();
 | 
						|
    });
 | 
						|
  };
 | 
						|
 | 
						|
  auto SortedUserList = [&](const MemoryDef *MD) {
 | 
						|
    std::vector<const MemoryDef *> Result;
 | 
						|
    transform(MD->users(), std::back_inserter(Result),
 | 
						|
              [](const User *U) { return cast<MemoryDef>(U); });
 | 
						|
    SortVecByID(Result);
 | 
						|
    return Result;
 | 
						|
  };
 | 
						|
 | 
						|
  // Use std::vectors, since they have nice pretty-printing if the test fails.
 | 
						|
  // Parens are necessary because EXPECT_EQ is a macro, and we have commas in
 | 
						|
  // our init lists...
 | 
						|
  EXPECT_EQ(SortedUserList(StoreAAccess),
 | 
						|
            (std::vector<const MemoryDef *>{StoreBAccess, StoreA2Access}));
 | 
						|
 | 
						|
  EXPECT_EQ(SortedUserList(StoreBAccess),
 | 
						|
            std::vector<const MemoryDef *>{StoreA2Access});
 | 
						|
 | 
						|
  // StoreAAccess should be present twice, since it uses liveOnEntry for both
 | 
						|
  // its defining and optimized accesses. This is a bit awkward, and is not
 | 
						|
  // relied upon anywhere at the moment. If this is painful, we can fix it.
 | 
						|
  EXPECT_EQ(SortedUserList(cast<MemoryDef>(MSSA.getLiveOnEntryDef())),
 | 
						|
            (std::vector<const MemoryDef *>{StoreAAccess, StoreAAccess,
 | 
						|
                                            StoreBAccess}));
 | 
						|
}
 | 
						|
 | 
						|
//   entry
 | 
						|
//     |
 | 
						|
//   header
 | 
						|
//    / \
 | 
						|
// body  |
 | 
						|
//    \ /
 | 
						|
//    exit
 | 
						|
// header:
 | 
						|
//  ; 1 = MemoryDef(liveOnEntry)
 | 
						|
// body:
 | 
						|
//  ; 2 = MemoryDef(1)
 | 
						|
// exit:
 | 
						|
//  ; 3 = MemoryPhi({body, 2}, {header, 1})
 | 
						|
//  ; 4 = MemoryDef(3); optimized to 3, cannot optimize thorugh phi.
 | 
						|
//  Insert edge: entry -> exit, check mssa Update is correct.
 | 
						|
TEST_F(MemorySSATest, TestAddedEdgeToBlockWithPhiNotOpt) {
 | 
						|
  F = Function::Create(
 | 
						|
      FunctionType::get(B.getVoidTy(), {B.getInt8PtrTy()}, false),
 | 
						|
      GlobalValue::ExternalLinkage, "F", &M);
 | 
						|
  Argument *PointerArg = &*F->arg_begin();
 | 
						|
  BasicBlock *Entry(BasicBlock::Create(C, "entry", F));
 | 
						|
  BasicBlock *Header(BasicBlock::Create(C, "header", F));
 | 
						|
  BasicBlock *Body(BasicBlock::Create(C, "body", F));
 | 
						|
  BasicBlock *Exit(BasicBlock::Create(C, "exit", F));
 | 
						|
  B.SetInsertPoint(Entry);
 | 
						|
  BranchInst::Create(Header, Entry);
 | 
						|
  B.SetInsertPoint(Header);
 | 
						|
  B.CreateStore(B.getInt8(16), PointerArg);
 | 
						|
  B.CreateCondBr(B.getTrue(), Exit, Body);
 | 
						|
  B.SetInsertPoint(Body);
 | 
						|
  B.CreateStore(B.getInt8(16), PointerArg);
 | 
						|
  BranchInst::Create(Exit, Body);
 | 
						|
  B.SetInsertPoint(Exit);
 | 
						|
  StoreInst *S1 = B.CreateStore(B.getInt8(16), PointerArg);
 | 
						|
 | 
						|
  setupAnalyses();
 | 
						|
  MemorySSA &MSSA = *Analyses->MSSA;
 | 
						|
  MemorySSAWalker *Walker = Analyses->Walker;
 | 
						|
  std::unique_ptr<MemorySSAUpdater> MSSAU =
 | 
						|
      make_unique<MemorySSAUpdater>(&MSSA);
 | 
						|
 | 
						|
  MemoryPhi *Phi = MSSA.getMemoryAccess(Exit);
 | 
						|
  EXPECT_EQ(Phi, Walker->getClobberingMemoryAccess(S1));
 | 
						|
 | 
						|
  // Alter CFG, add edge: entry -> exit
 | 
						|
  Entry->getTerminator()->eraseFromParent();
 | 
						|
  B.SetInsertPoint(Entry);
 | 
						|
  B.CreateCondBr(B.getTrue(), Header, Exit);
 | 
						|
  SmallVector<CFGUpdate, 1> Updates;
 | 
						|
  Updates.push_back({cfg::UpdateKind::Insert, Entry, Exit});
 | 
						|
  Analyses->DT.applyUpdates(Updates);
 | 
						|
  MSSAU->applyInsertUpdates(Updates, Analyses->DT);
 | 
						|
  EXPECT_EQ(Phi, Walker->getClobberingMemoryAccess(S1));
 | 
						|
}
 | 
						|
 | 
						|
//   entry
 | 
						|
//     |
 | 
						|
//   header
 | 
						|
//    / \
 | 
						|
// body  |
 | 
						|
//    \ /
 | 
						|
//    exit
 | 
						|
// header:
 | 
						|
//  ; 1 = MemoryDef(liveOnEntry)
 | 
						|
// body:
 | 
						|
//  ; 2 = MemoryDef(1)
 | 
						|
// exit:
 | 
						|
//  ; 3 = MemoryPhi({body, 2}, {header, 1})
 | 
						|
//  ; 4 = MemoryDef(3); optimize this to 1 now, added edge should invalidate
 | 
						|
//  the optimized access.
 | 
						|
//  Insert edge: entry -> exit, check mssa Update is correct.
 | 
						|
TEST_F(MemorySSATest, TestAddedEdgeToBlockWithPhiOpt) {
 | 
						|
  F = Function::Create(
 | 
						|
      FunctionType::get(B.getVoidTy(), {B.getInt8PtrTy()}, false),
 | 
						|
      GlobalValue::ExternalLinkage, "F", &M);
 | 
						|
  Argument *PointerArg = &*F->arg_begin();
 | 
						|
  Type *Int8 = Type::getInt8Ty(C);
 | 
						|
  BasicBlock *Entry(BasicBlock::Create(C, "entry", F));
 | 
						|
  BasicBlock *Header(BasicBlock::Create(C, "header", F));
 | 
						|
  BasicBlock *Body(BasicBlock::Create(C, "body", F));
 | 
						|
  BasicBlock *Exit(BasicBlock::Create(C, "exit", F));
 | 
						|
 | 
						|
  B.SetInsertPoint(Entry);
 | 
						|
  Value *Alloca = B.CreateAlloca(Int8, ConstantInt::get(Int8, 1), "A");
 | 
						|
  BranchInst::Create(Header, Entry);
 | 
						|
 | 
						|
  B.SetInsertPoint(Header);
 | 
						|
  StoreInst *S1 = B.CreateStore(B.getInt8(16), PointerArg);
 | 
						|
  B.CreateCondBr(B.getTrue(), Exit, Body);
 | 
						|
 | 
						|
  B.SetInsertPoint(Body);
 | 
						|
  B.CreateStore(ConstantInt::get(Int8, 0), Alloca);
 | 
						|
  BranchInst::Create(Exit, Body);
 | 
						|
 | 
						|
  B.SetInsertPoint(Exit);
 | 
						|
  StoreInst *S2 = B.CreateStore(B.getInt8(16), PointerArg);
 | 
						|
 | 
						|
  setupAnalyses();
 | 
						|
  MemorySSA &MSSA = *Analyses->MSSA;
 | 
						|
  MemorySSAWalker *Walker = Analyses->Walker;
 | 
						|
  std::unique_ptr<MemorySSAUpdater> MSSAU =
 | 
						|
      make_unique<MemorySSAUpdater>(&MSSA);
 | 
						|
 | 
						|
  MemoryDef *DefS1 = cast<MemoryDef>(MSSA.getMemoryAccess(S1));
 | 
						|
  EXPECT_EQ(DefS1, Walker->getClobberingMemoryAccess(S2));
 | 
						|
 | 
						|
  // Alter CFG, add edge: entry -> exit
 | 
						|
  Entry->getTerminator()->eraseFromParent();
 | 
						|
  B.SetInsertPoint(Entry);
 | 
						|
  B.CreateCondBr(B.getTrue(), Header, Exit);
 | 
						|
  SmallVector<CFGUpdate, 1> Updates;
 | 
						|
  Updates.push_back({cfg::UpdateKind::Insert, Entry, Exit});
 | 
						|
  Analyses->DT.applyUpdates(Updates);
 | 
						|
  MSSAU->applyInsertUpdates(Updates, Analyses->DT);
 | 
						|
 | 
						|
  MemoryPhi *Phi = MSSA.getMemoryAccess(Exit);
 | 
						|
  EXPECT_EQ(Phi, Walker->getClobberingMemoryAccess(S2));
 | 
						|
}
 | 
						|
 | 
						|
//   entry
 | 
						|
//    /  |
 | 
						|
//   a   |
 | 
						|
//  / \  |
 | 
						|
//  b c  f
 | 
						|
//  \ /  |
 | 
						|
//   d   |
 | 
						|
//    \ /
 | 
						|
//     e
 | 
						|
// f:
 | 
						|
//  ; 1 = MemoryDef(liveOnEntry)
 | 
						|
// e:
 | 
						|
//  ; 2 = MemoryPhi({d, liveOnEntry}, {f, 1})
 | 
						|
//
 | 
						|
// Insert edge: f -> c, check update is correct.
 | 
						|
// After update:
 | 
						|
// f:
 | 
						|
//  ; 1 = MemoryDef(liveOnEntry)
 | 
						|
// c:
 | 
						|
//  ; 3 = MemoryPhi({a, liveOnEntry}, {f, 1})
 | 
						|
// d:
 | 
						|
//  ; 4 = MemoryPhi({b, liveOnEntry}, {c, 3})
 | 
						|
// e:
 | 
						|
//  ; 2 = MemoryPhi({d, 4}, {f, 1})
 | 
						|
TEST_F(MemorySSATest, TestAddedEdgeToBlockWithNoPhiAddNewPhis) {
 | 
						|
  F = Function::Create(
 | 
						|
      FunctionType::get(B.getVoidTy(), {B.getInt8PtrTy()}, false),
 | 
						|
      GlobalValue::ExternalLinkage, "F", &M);
 | 
						|
  Argument *PointerArg = &*F->arg_begin();
 | 
						|
  BasicBlock *Entry(BasicBlock::Create(C, "entry", F));
 | 
						|
  BasicBlock *ABlock(BasicBlock::Create(C, "a", F));
 | 
						|
  BasicBlock *BBlock(BasicBlock::Create(C, "b", F));
 | 
						|
  BasicBlock *CBlock(BasicBlock::Create(C, "c", F));
 | 
						|
  BasicBlock *DBlock(BasicBlock::Create(C, "d", F));
 | 
						|
  BasicBlock *EBlock(BasicBlock::Create(C, "e", F));
 | 
						|
  BasicBlock *FBlock(BasicBlock::Create(C, "f", F));
 | 
						|
 | 
						|
  B.SetInsertPoint(Entry);
 | 
						|
  B.CreateCondBr(B.getTrue(), ABlock, FBlock);
 | 
						|
  B.SetInsertPoint(ABlock);
 | 
						|
  B.CreateCondBr(B.getTrue(), BBlock, CBlock);
 | 
						|
  B.SetInsertPoint(BBlock);
 | 
						|
  BranchInst::Create(DBlock, BBlock);
 | 
						|
  B.SetInsertPoint(CBlock);
 | 
						|
  BranchInst::Create(DBlock, CBlock);
 | 
						|
  B.SetInsertPoint(DBlock);
 | 
						|
  BranchInst::Create(EBlock, DBlock);
 | 
						|
  B.SetInsertPoint(FBlock);
 | 
						|
  B.CreateStore(B.getInt8(16), PointerArg);
 | 
						|
  BranchInst::Create(EBlock, FBlock);
 | 
						|
 | 
						|
  setupAnalyses();
 | 
						|
  MemorySSA &MSSA = *Analyses->MSSA;
 | 
						|
  std::unique_ptr<MemorySSAUpdater> MSSAU =
 | 
						|
      make_unique<MemorySSAUpdater>(&MSSA);
 | 
						|
 | 
						|
  // Alter CFG, add edge: f -> c
 | 
						|
  FBlock->getTerminator()->eraseFromParent();
 | 
						|
  B.SetInsertPoint(FBlock);
 | 
						|
  B.CreateCondBr(B.getTrue(), CBlock, EBlock);
 | 
						|
  SmallVector<CFGUpdate, 1> Updates;
 | 
						|
  Updates.push_back({cfg::UpdateKind::Insert, FBlock, CBlock});
 | 
						|
  Analyses->DT.applyUpdates(Updates);
 | 
						|
  MSSAU->applyInsertUpdates(Updates, Analyses->DT);
 | 
						|
 | 
						|
  MemoryPhi *MPC = MSSA.getMemoryAccess(CBlock);
 | 
						|
  EXPECT_NE(MPC, nullptr);
 | 
						|
  MemoryPhi *MPD = MSSA.getMemoryAccess(DBlock);
 | 
						|
  EXPECT_NE(MPD, nullptr);
 | 
						|
  MemoryPhi *MPE = MSSA.getMemoryAccess(EBlock);
 | 
						|
  EXPECT_EQ(MPD, MPE->getIncomingValueForBlock(DBlock));
 | 
						|
}
 |