Skip to content

Commit

Permalink
Add support for invariant.start inside the static constructor evaluat…
Browse files Browse the repository at this point in the history
…or. 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
  • Loading branch information
nlewycky committed Feb 17, 2012
1 parent 38bdc57 commit 81266c5
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 12 deletions.
59 changes: 47 additions & 12 deletions lib/Transforms/IPO/GlobalOpt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2295,6 +2295,7 @@ static bool EvaluateFunction(Function *F, Constant *&RetVal,
DenseMap<Constant*, Constant*> &MutatedMemory,
std::vector<GlobalVariable*> &AllocaTmps,
SmallPtrSet<Constant*, 8> &SimpleConstants,
SmallPtrSet<GlobalVariable*, 8> &Invariants,
const TargetData *TD,
const TargetLibraryInfo *TLI);

Expand All @@ -2307,6 +2308,7 @@ static bool EvaluateBlock(BasicBlock::iterator CurInst, BasicBlock *&NextBB,
DenseMap<Constant*, Constant*> &MutatedMemory,
std::vector<GlobalVariable*> &AllocaTmps,
SmallPtrSet<Constant*, 8> &SimpleConstants,
SmallPtrSet<GlobalVariable*, 8> &Invariants,
const TargetData *TD,
const TargetLibraryInfo *TLI) {
// This is the main evaluation loop.
Expand Down Expand Up @@ -2415,14 +2417,39 @@ static bool EvaluateBlock(BasicBlock::iterator CurInst, BasicBlock *&NextBB,
// Cannot handle inline asm.
if (isa<InlineAsm>(CS.getCalledValue())) return false;

if (MemSetInst *MSI = dyn_cast<MemSetInst>(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<IntrinsicInst>(CS.getInstruction())) {
if (MemSetInst *MSI = dyn_cast<MemSetInst>(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<ConstantInt>(II->getArgOperand(0));
if (Size->isAllOnesValue()) {
Value *PtrArg = getVal(Values, II->getArgOperand(1));
Value *Ptr = PtrArg->stripPointerCasts();
if (GlobalVariable *GV = dyn_cast<GlobalVariable>(Ptr))
Invariants.insert(GV);
}
// Continue even if we do nothing.
++CurInst;
continue;
}
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -2521,6 +2548,7 @@ static bool EvaluateFunction(Function *F, Constant *&RetVal,
DenseMap<Constant*, Constant*> &MutatedMemory,
std::vector<GlobalVariable*> &AllocaTmps,
SmallPtrSet<Constant*, 8> &SimpleConstants,
SmallPtrSet<GlobalVariable*, 8> &Invariants,
const TargetData *TD,
const TargetLibraryInfo *TLI) {
// Check to see if this function is already executing (recursion). If so,
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -2607,12 +2635,16 @@ static bool EvaluateStaticConstructor(Function *F, const TargetData *TD,
// simple enough to live in a static initializer of a global.
SmallPtrSet<Constant*, 8> SimpleConstants;

// Invariants - These global variables have been marked invariant by the
// static constructor.
SmallPtrSet<GlobalVariable*, 8> Invariants;

// Call the function.
Constant *RetValDummy;
bool EvalSuccess = EvaluateFunction(F, RetValDummy,
SmallVector<Constant*, 0>(), CallStack,
MutatedMemory, AllocaTmps,
SimpleConstants, TD, TLI);
SimpleConstants, Invariants, TD, TLI);

if (EvalSuccess) {
// We succeeded at evaluation: commit the result.
Expand All @@ -2622,6 +2654,9 @@ static bool EvaluateStaticConstructor(Function *F, const TargetData *TD,
for (DenseMap<Constant*, Constant*>::iterator I = MutatedMemory.begin(),
E = MutatedMemory.end(); I != E; ++I)
CommitValueTo(I->second, I->first);
for (SmallPtrSet<GlobalVariable*, 8>::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'
Expand Down
34 changes: 34 additions & 0 deletions test/Transforms/GlobalOpt/invariant.ll
Original file line number Diff line number Diff line change
@@ -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 } ]

0 comments on commit 81266c5

Please sign in to comment.