[Evaluator] Evaluate load/store with bitcast

Differential revision: https://reviews.llvm.org/D43457

llvm-svn: 327381
This commit is contained in:
Eugene Leviant 2018-03-13 10:19:50 +00:00
parent cd3cbd4c1f
commit 6f42a2cd91
4 changed files with 95 additions and 46 deletions

View File

@ -147,6 +147,12 @@ Constant *ConstantFoldCall(ImmutableCallSite CS, Function *F,
ArrayRef<Constant *> Operands,
const TargetLibraryInfo *TLI = nullptr);
/// ConstantFoldLoadThroughBitcast - try to cast constant to destination type
/// returning null if unsuccessful. Can cast pointer to pointer or pointer to
/// integer and vice versa if their sizes are equal.
Constant *ConstantFoldLoadThroughBitcast(Constant *C, Type *DestTy,
const DataLayout &DL);
/// \brief Check whether the given call has no side-effects.
/// Specifically checks for math routimes which sometimes set errno.
bool isMathLibCallNoop(CallSite CS, const TargetLibraryInfo *TLI);

View File

@ -320,6 +320,41 @@ bool llvm::IsConstantOffsetFromGlobal(Constant *C, GlobalValue *&GV,
return true;
}
Constant *llvm::ConstantFoldLoadThroughBitcast(Constant *C, Type *DestTy,
const DataLayout &DL) {
do {
Type *SrcTy = C->getType();
// If the type sizes are the same and a cast is legal, just directly
// cast the constant.
if (DL.getTypeSizeInBits(DestTy) == DL.getTypeSizeInBits(SrcTy)) {
Instruction::CastOps Cast = Instruction::BitCast;
// If we are going from a pointer to int or vice versa, we spell the cast
// differently.
if (SrcTy->isIntegerTy() && DestTy->isPointerTy())
Cast = Instruction::IntToPtr;
else if (SrcTy->isPointerTy() && DestTy->isIntegerTy())
Cast = Instruction::PtrToInt;
if (CastInst::castIsValid(Cast, C, DestTy))
return ConstantExpr::getCast(Cast, C, DestTy);
}
// If this isn't an aggregate type, there is nothing we can do to drill down
// and find a bitcastable constant.
if (!SrcTy->isAggregateType())
return nullptr;
// We're simulating a load through a pointer that was bitcast to point to
// a different type, so we can try to walk down through the initial
// elements of an aggregate to see if some part of th e aggregate is
// castable to implement the "load" semantic model.
C = C->getAggregateElement(0u);
} while (C);
return nullptr;
}
namespace {
/// Recursive helper to read bits out of global. C is the constant being copied
@ -537,8 +572,8 @@ Constant *FoldReinterpretLoadFromConstPtr(Constant *C, Type *LoadTy,
return ConstantInt::get(IntType->getContext(), ResultVal);
}
Constant *ConstantFoldLoadThroughBitcast(ConstantExpr *CE, Type *DestTy,
const DataLayout &DL) {
Constant *ConstantFoldLoadThroughBitcastExpr(ConstantExpr *CE, Type *DestTy,
const DataLayout &DL) {
auto *SrcPtr = CE->getOperand(0);
auto *SrcPtrTy = dyn_cast<PointerType>(SrcPtr->getType());
if (!SrcPtrTy)
@ -549,37 +584,7 @@ Constant *ConstantFoldLoadThroughBitcast(ConstantExpr *CE, Type *DestTy,
if (!C)
return nullptr;
do {
Type *SrcTy = C->getType();
// If the type sizes are the same and a cast is legal, just directly
// cast the constant.
if (DL.getTypeSizeInBits(DestTy) == DL.getTypeSizeInBits(SrcTy)) {
Instruction::CastOps Cast = Instruction::BitCast;
// If we are going from a pointer to int or vice versa, we spell the cast
// differently.
if (SrcTy->isIntegerTy() && DestTy->isPointerTy())
Cast = Instruction::IntToPtr;
else if (SrcTy->isPointerTy() && DestTy->isIntegerTy())
Cast = Instruction::PtrToInt;
if (CastInst::castIsValid(Cast, C, DestTy))
return ConstantExpr::getCast(Cast, C, DestTy);
}
// If this isn't an aggregate type, there is nothing we can do to drill down
// and find a bitcastable constant.
if (!SrcTy->isAggregateType())
return nullptr;
// We're simulating a load through a pointer that was bitcast to point to
// a different type, so we can try to walk down through the initial
// elements of an aggregate to see if some part of th e aggregate is
// castable to implement the "load" semantic model.
C = C->getAggregateElement(0u);
} while (C);
return nullptr;
return llvm::ConstantFoldLoadThroughBitcast(C, DestTy, DL);
}
} // end anonymous namespace
@ -611,7 +616,7 @@ Constant *llvm::ConstantFoldLoadFromConstPtr(Constant *C, Type *Ty,
}
if (CE->getOpcode() == Instruction::BitCast)
if (Constant *LoadedC = ConstantFoldLoadThroughBitcast(CE, Ty, DL))
if (Constant *LoadedC = ConstantFoldLoadThroughBitcastExpr(CE, Ty, DL))
return LoadedC;
// Instead of loading constant c string, use corresponding integer value

View File

@ -174,6 +174,11 @@ static bool isSimpleEnoughPointerToCommit(Constant *C) {
return false;
}
static Constant *getInitializer(Constant *C) {
auto *GV = dyn_cast<GlobalVariable>(C);
return GV && GV->hasDefinitiveInitializer() ? GV->getInitializer() : nullptr;
}
/// Return the value that would be computed by a load from P after the stores
/// reflected by 'memory' have been performed. If we can't decide, return null.
Constant *Evaluator::ComputeLoadResult(Constant *P) {
@ -189,14 +194,21 @@ Constant *Evaluator::ComputeLoadResult(Constant *P) {
return nullptr;
}
// Handle a constantexpr getelementptr.
if (ConstantExpr *CE = dyn_cast<ConstantExpr>(P))
if (CE->getOpcode() == Instruction::GetElementPtr &&
isa<GlobalVariable>(CE->getOperand(0))) {
GlobalVariable *GV = cast<GlobalVariable>(CE->getOperand(0));
if (GV->hasDefinitiveInitializer())
return ConstantFoldLoadThroughGEPConstantExpr(GV->getInitializer(), CE);
if (ConstantExpr *CE = dyn_cast<ConstantExpr>(P)) {
switch (CE->getOpcode()) {
// Handle a constantexpr getelementptr.
case Instruction::GetElementPtr:
if (auto *I = getInitializer(CE->getOperand(0)))
return ConstantFoldLoadThroughGEPConstantExpr(I, CE);
break;
// Handle a constantexpr bitcast.
case Instruction::BitCast:
if (auto *I = getInitializer(CE->getOperand(0)))
return ConstantFoldLoadThroughBitcast(
I, P->getType()->getPointerElementType(), DL);
break;
}
}
return nullptr; // don't know how to evaluate.
}
@ -252,7 +264,8 @@ bool Evaluator::EvaluateBlock(BasicBlock::iterator CurInst,
// In order to push the bitcast onto the stored value, a bitcast
// from NewTy to Val's type must be legal. If it's not, we can try
// introspecting NewTy to find a legal conversion.
while (!Val->getType()->canLosslesslyBitCastTo(NewTy)) {
Constant *NewVal;
while (!(NewVal = ConstantFoldLoadThroughBitcast(Val, NewTy, DL))) {
// If NewTy is a struct, we can convert the pointer to the struct
// into a pointer to its first member.
// FIXME: This could be extended to support arrays as well.
@ -276,10 +289,7 @@ bool Evaluator::EvaluateBlock(BasicBlock::iterator CurInst,
}
}
// If we found compatible types, go ahead and push the bitcast
// onto the stored value.
Val = ConstantExpr::getBitCast(Val, NewTy);
Val = NewVal;
DEBUG(dbgs() << "Evaluated bitcast: " << *Val << "\n");
}
}

View File

@ -0,0 +1,28 @@
; RUN: opt -globalopt -instcombine %s -S -o - | FileCheck %s
; Static constructor should have been optimized out
; CHECK: i32 @main
; CHECK-NEXT: ret i32 69905
; CHECK-NOT: _GLOBAL__sub_I_main.cpp
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-linux-gnu"
%struct.S = type { %struct.A* }
%struct.A = type { i64, i64 }
@s = internal local_unnamed_addr global %struct.S zeroinitializer, align 8
@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I_main.cpp, i8* null }]
@gA = available_externally dso_local local_unnamed_addr global %struct.A* inttoptr (i64 69905 to %struct.A*), align 8
define dso_local i32 @main() local_unnamed_addr {
%1 = load i64, i64* bitcast (%struct.S* @s to i64*), align 8
%2 = trunc i64 %1 to i32
ret i32 %2
}
define internal void @_GLOBAL__sub_I_main.cpp() section ".text.startup" {
%1 = load i64, i64* bitcast (%struct.A** @gA to i64*), align 8
store i64 %1, i64* bitcast (%struct.S* @s to i64*), align 8
ret void
}