mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 18:54:02 +01:00
[Evaluator] Evaluate load/store with bitcast
Differential revision: https://reviews.llvm.org/D43457 llvm-svn: 327381
This commit is contained in:
parent
e106c93d00
commit
2069c38e0c
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
28
test/Transforms/GlobalOpt/evaluate-bitcast.ll
Normal file
28
test/Transforms/GlobalOpt/evaluate-bitcast.ll
Normal 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
|
||||
}
|
Loading…
Reference in New Issue
Block a user