From 81266c5c9358d71331886a98e750ac9409cc640c Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Fri, 17 Feb 2012 06:59:21 +0000 Subject: [PATCH] Add support for invariant.start inside the static constructor evaluator. This is useful to represent a variable that is const in the source but can't be constant in the IR because of a non-trivial constructor. If globalopt evaluates the constructor, and there was an invariant.start with no matching invariant.end possible, it will mark the global constant afterwards. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@150794 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Transforms/IPO/GlobalOpt.cpp | 59 ++++++++++++++++++++------ test/Transforms/GlobalOpt/invariant.ll | 34 +++++++++++++++ 2 files changed, 81 insertions(+), 12 deletions(-) create mode 100644 test/Transforms/GlobalOpt/invariant.ll diff --git a/lib/Transforms/IPO/GlobalOpt.cpp b/lib/Transforms/IPO/GlobalOpt.cpp index d959a223cac..f395176bce5 100644 --- a/lib/Transforms/IPO/GlobalOpt.cpp +++ b/lib/Transforms/IPO/GlobalOpt.cpp @@ -2295,6 +2295,7 @@ static bool EvaluateFunction(Function *F, Constant *&RetVal, DenseMap &MutatedMemory, std::vector &AllocaTmps, SmallPtrSet &SimpleConstants, + SmallPtrSet &Invariants, const TargetData *TD, const TargetLibraryInfo *TLI); @@ -2307,6 +2308,7 @@ static bool EvaluateBlock(BasicBlock::iterator CurInst, BasicBlock *&NextBB, DenseMap &MutatedMemory, std::vector &AllocaTmps, SmallPtrSet &SimpleConstants, + SmallPtrSet &Invariants, const TargetData *TD, const TargetLibraryInfo *TLI) { // This is the main evaluation loop. @@ -2415,14 +2417,39 @@ static bool EvaluateBlock(BasicBlock::iterator CurInst, BasicBlock *&NextBB, // Cannot handle inline asm. if (isa(CS.getCalledValue())) return false; - if (MemSetInst *MSI = dyn_cast(CS.getInstruction())) { - if (MSI->isVolatile()) return false; - Constant *Ptr = getVal(Values, MSI->getDest()); - Constant *Val = getVal(Values, MSI->getValue()); - Constant *DestVal = ComputeLoadResult(getVal(Values, Ptr), - MutatedMemory); - if (Val->isNullValue() && DestVal && DestVal->isNullValue()) { - // This memset is a no-op. + if (IntrinsicInst *II = dyn_cast(CS.getInstruction())) { + if (MemSetInst *MSI = dyn_cast(II)) { + if (MSI->isVolatile()) return false; + Constant *Ptr = getVal(Values, MSI->getDest()); + Constant *Val = getVal(Values, MSI->getValue()); + Constant *DestVal = ComputeLoadResult(getVal(Values, Ptr), + MutatedMemory); + if (Val->isNullValue() && DestVal && DestVal->isNullValue()) { + // This memset is a no-op. + ++CurInst; + continue; + } + } + + if (II->getIntrinsicID() == Intrinsic::lifetime_start || + II->getIntrinsicID() == Intrinsic::lifetime_end) { + ++CurInst; + continue; + } + + if (II->getIntrinsicID() == Intrinsic::invariant_start) { + // We don't insert an entry into Values, as it doesn't have a + // meaningful return value. + if (!II->use_empty()) + return false; + ConstantInt *Size = cast(II->getArgOperand(0)); + if (Size->isAllOnesValue()) { + Value *PtrArg = getVal(Values, II->getArgOperand(1)); + Value *Ptr = PtrArg->stripPointerCasts(); + if (GlobalVariable *GV = dyn_cast(Ptr)) + Invariants.insert(GV); + } + // Continue even if we do nothing. ++CurInst; continue; } @@ -2453,8 +2480,8 @@ static bool EvaluateBlock(BasicBlock::iterator CurInst, BasicBlock *&NextBB, Constant *RetVal; // Execute the call, if successful, use the return value. if (!EvaluateFunction(Callee, RetVal, Formals, CallStack, - MutatedMemory, AllocaTmps, SimpleConstants, TD, - TLI)) + MutatedMemory, AllocaTmps, SimpleConstants, + Invariants, TD, TLI)) return false; InstResult = RetVal; @@ -2521,6 +2548,7 @@ static bool EvaluateFunction(Function *F, Constant *&RetVal, DenseMap &MutatedMemory, std::vector &AllocaTmps, SmallPtrSet &SimpleConstants, + SmallPtrSet &Invariants, const TargetData *TD, const TargetLibraryInfo *TLI) { // Check to see if this function is already executing (recursion). If so, @@ -2552,7 +2580,7 @@ static bool EvaluateFunction(Function *F, Constant *&RetVal, while (1) { BasicBlock *NextBB; if (!EvaluateBlock(CurInst, NextBB, CallStack, Values, MutatedMemory, - AllocaTmps, SimpleConstants, TD, TLI)) + AllocaTmps, SimpleConstants, Invariants, TD, TLI)) return false; if (NextBB == 0) { @@ -2607,12 +2635,16 @@ static bool EvaluateStaticConstructor(Function *F, const TargetData *TD, // simple enough to live in a static initializer of a global. SmallPtrSet SimpleConstants; + // Invariants - These global variables have been marked invariant by the + // static constructor. + SmallPtrSet Invariants; + // Call the function. Constant *RetValDummy; bool EvalSuccess = EvaluateFunction(F, RetValDummy, SmallVector(), CallStack, MutatedMemory, AllocaTmps, - SimpleConstants, TD, TLI); + SimpleConstants, Invariants, TD, TLI); if (EvalSuccess) { // We succeeded at evaluation: commit the result. @@ -2622,6 +2654,9 @@ static bool EvaluateStaticConstructor(Function *F, const TargetData *TD, for (DenseMap::iterator I = MutatedMemory.begin(), E = MutatedMemory.end(); I != E; ++I) CommitValueTo(I->second, I->first); + for (SmallPtrSet::iterator I = Invariants.begin(), + E = Invariants.end(); I != E; ++I) + (*I)->setConstant(true); } // At this point, we are done interpreting. If we created any 'alloca' diff --git a/test/Transforms/GlobalOpt/invariant.ll b/test/Transforms/GlobalOpt/invariant.ll new file mode 100644 index 00000000000..2662d60b9bc --- /dev/null +++ b/test/Transforms/GlobalOpt/invariant.ll @@ -0,0 +1,34 @@ +; RUN: opt -globalopt -S -o - < %s | FileCheck %s + +declare {}* @llvm.invariant.start(i64 %size, i8* nocapture %ptr) + +define void @test1(i8* %ptr) { + call {}* @llvm.invariant.start(i64 -1, i8* %ptr) + ret void +} + +@object1 = global i32 0 +; CHECK: @object1 = constant i32 -1 +define void @ctor1() { + store i32 -1, i32* @object1 + %A = bitcast i32* @object1 to i8* + call void @test1(i8* %A) + ret void +} + + +@object2 = global i32 0 +; CHECK: @object2 = global i32 0 +define void @ctor2() { + store i32 -1, i32* @object2 + %A = bitcast i32* @object2 to i8* + %B = call {}* @llvm.invariant.start(i64 -1, i8* %A) + ; Why in the world does this pass the verifier? + %C = bitcast {}* %B to i8* + ret void +} + +@llvm.global_ctors = appending constant + [2 x { i32, void ()* }] + [ { i32, void ()* } { i32 65535, void ()* @ctor1 }, + { i32, void ()* } { i32 65535, void ()* @ctor2 } ]