mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-07-27 12:26:08 +00:00
Revert r86359, it is breaking the self host on the
llvm-gcc-i386-darwin9 build bot. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@86391 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -78,84 +78,19 @@ static RegisterPass<DSE> X("dse", "Dead Store Elimination");
|
|||||||
|
|
||||||
FunctionPass *llvm::createDeadStoreEliminationPass() { return new DSE(); }
|
FunctionPass *llvm::createDeadStoreEliminationPass() { return new DSE(); }
|
||||||
|
|
||||||
/// doesClobberMemory - Does this instruction clobber (write without reading)
|
/// isValueAtLeastAsBigAs - Return true if V1 is greater than or equal to the
|
||||||
/// some memory?
|
/// stored size of V2. This returns false if we don't know.
|
||||||
static bool doesClobberMemory(Instruction *I) {
|
|
||||||
if (isa<StoreInst>(I))
|
|
||||||
return true;
|
|
||||||
if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(I)) {
|
|
||||||
switch (II->getIntrinsicID()) {
|
|
||||||
default: return false;
|
|
||||||
case Intrinsic::memset: case Intrinsic::memmove: case Intrinsic::memcpy:
|
|
||||||
case Intrinsic::lifetime_end: return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// isElidable - If the memory this instruction and the memory it writes to is
|
|
||||||
/// unused, may we delete this instrtction?
|
|
||||||
static bool isElidable(Instruction *I) {
|
|
||||||
assert(doesClobberMemory(I));
|
|
||||||
if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(I))
|
|
||||||
return II->getIntrinsicID() != Intrinsic::lifetime_end;
|
|
||||||
if (StoreInst *SI = dyn_cast<StoreInst>(I))
|
|
||||||
return !SI->isVolatile();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// getPointerOperand - Return the pointer that is being clobbered.
|
|
||||||
static Value *getPointerOperand(Instruction *I) {
|
|
||||||
assert(doesClobberMemory(I));
|
|
||||||
if (StoreInst *SI = dyn_cast<StoreInst>(I))
|
|
||||||
return SI->getPointerOperand();
|
|
||||||
if (MemIntrinsic *MI = dyn_cast<MemIntrinsic>(I))
|
|
||||||
return MI->getOperand(1);
|
|
||||||
assert(cast<IntrinsicInst>(I)->getIntrinsicID() == Intrinsic::lifetime_end);
|
|
||||||
return cast<IntrinsicInst>(I)->getOperand(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// getStoreSize - Return the length in bytes of the write by the clobbering
|
|
||||||
/// instruction. If variable or unknown, returns -1.
|
|
||||||
static unsigned getStoreSize(Instruction *I, const TargetData *TD = 0) {
|
|
||||||
assert(doesClobberMemory(I));
|
|
||||||
if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
|
|
||||||
if (!TD) return -1u;
|
|
||||||
const PointerType *PTy =
|
|
||||||
cast<PointerType>(SI->getPointerOperand()->getType());
|
|
||||||
return TD->getTypeStoreSize(PTy);
|
|
||||||
}
|
|
||||||
|
|
||||||
Value *Len;
|
|
||||||
if (MemIntrinsic *MI = dyn_cast<MemIntrinsic>(I)) {
|
|
||||||
Len = MI->getLength();
|
|
||||||
} else {
|
|
||||||
assert(cast<IntrinsicInst>(I)->getIntrinsicID() ==
|
|
||||||
Intrinsic::lifetime_end);
|
|
||||||
Len = cast<IntrinsicInst>(I)->getOperand(0);
|
|
||||||
}
|
|
||||||
if (ConstantInt *LenCI = dyn_cast<ConstantInt>(Len))
|
|
||||||
if (!LenCI->isAllOnesValue())
|
|
||||||
return LenCI->getZExtValue();
|
|
||||||
return -1u;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// isStoreAtLeastAsWideAs - Return true if the size of the store in I1 is
|
|
||||||
/// greater than or equal to the store in I2. This returns false if we don't
|
|
||||||
/// know.
|
|
||||||
///
|
///
|
||||||
static bool isStoreAtLeastAsWideAs(Instruction *I1, Instruction *I2,
|
static bool isValueAtLeastAsBigAs(Value *V1, Value *V2, const TargetData *TD) {
|
||||||
const TargetData *TD) {
|
const Type *V1Ty = V1->getType(), *V2Ty = V2->getType();
|
||||||
const Type *I1Ty = getPointerOperand(I1)->getType();
|
|
||||||
const Type *I2Ty = getPointerOperand(I2)->getType();
|
|
||||||
|
|
||||||
// Exactly the same type, must have exactly the same size.
|
// Exactly the same type, must have exactly the same size.
|
||||||
if (I1Ty == I2Ty) return true;
|
if (V1Ty == V2Ty) return true;
|
||||||
|
|
||||||
int I1Size = getStoreSize(I1, TD);
|
// If we don't have target data, we don't know.
|
||||||
int I2Size = getStoreSize(I2, TD);
|
if (TD == 0) return false;
|
||||||
|
|
||||||
return I1Size != -1 && I2Size != -1 && I1Size >= I2Size;
|
return TD->getTypeStoreSize(V1Ty) >= TD->getTypeStoreSize(V2Ty);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DSE::runOnBasicBlock(BasicBlock &BB) {
|
bool DSE::runOnBasicBlock(BasicBlock &BB) {
|
||||||
@@ -169,9 +104,14 @@ bool DSE::runOnBasicBlock(BasicBlock &BB) {
|
|||||||
Instruction *Inst = BBI++;
|
Instruction *Inst = BBI++;
|
||||||
|
|
||||||
// If we find a store or a free, get its memory dependence.
|
// If we find a store or a free, get its memory dependence.
|
||||||
if (!doesClobberMemory(Inst) && !isFreeCall(Inst))
|
if (!isa<StoreInst>(Inst) && !isFreeCall(Inst))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// Don't molest volatile stores or do queries that will return "clobber".
|
||||||
|
if (StoreInst *SI = dyn_cast<StoreInst>(Inst))
|
||||||
|
if (SI->isVolatile())
|
||||||
|
continue;
|
||||||
|
|
||||||
MemDepResult InstDep = MD.getDependency(Inst);
|
MemDepResult InstDep = MD.getDependency(Inst);
|
||||||
|
|
||||||
// Ignore non-local stores.
|
// Ignore non-local stores.
|
||||||
@@ -184,16 +124,16 @@ bool DSE::runOnBasicBlock(BasicBlock &BB) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StoreInst *SI = cast<StoreInst>(Inst);
|
||||||
|
|
||||||
// If not a definite must-alias dependency, ignore it.
|
// If not a definite must-alias dependency, ignore it.
|
||||||
if (!InstDep.isDef())
|
if (!InstDep.isDef())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// If this is a store-store dependence, then the previous store is dead so
|
// If this is a store-store dependence, then the previous store is dead so
|
||||||
// long as this store is at least as big as it.
|
// long as this store is at least as big as it.
|
||||||
if (doesClobberMemory(InstDep.getInst())) {
|
if (StoreInst *DepStore = dyn_cast<StoreInst>(InstDep.getInst()))
|
||||||
Instruction *DepStore = InstDep.getInst();
|
if (isValueAtLeastAsBigAs(SI->getOperand(0), DepStore->getOperand(0),TD)){
|
||||||
if (isStoreAtLeastAsWideAs(Inst, DepStore, TD) &&
|
|
||||||
isElidable(DepStore)){
|
|
||||||
// Delete the store and now-dead instructions that feed it.
|
// Delete the store and now-dead instructions that feed it.
|
||||||
DeleteDeadInstruction(DepStore);
|
DeleteDeadInstruction(DepStore);
|
||||||
NumFastStores++;
|
NumFastStores++;
|
||||||
@@ -206,31 +146,25 @@ bool DSE::runOnBasicBlock(BasicBlock &BB) {
|
|||||||
--BBI;
|
--BBI;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!isElidable(Inst))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// If we're storing the same value back to a pointer that we just
|
// If we're storing the same value back to a pointer that we just
|
||||||
// loaded from, then the store can be removed.
|
// loaded from, then the store can be removed.
|
||||||
if (StoreInst *SI = dyn_cast<StoreInst>(Inst)) {
|
if (LoadInst *DepLoad = dyn_cast<LoadInst>(InstDep.getInst())) {
|
||||||
if (LoadInst *DepLoad = dyn_cast<LoadInst>(InstDep.getInst())) {
|
if (SI->getPointerOperand() == DepLoad->getPointerOperand() &&
|
||||||
if (SI->getPointerOperand() == DepLoad->getPointerOperand() &&
|
SI->getOperand(0) == DepLoad) {
|
||||||
SI->getOperand(0) == DepLoad) {
|
// DeleteDeadInstruction can delete the current instruction. Save BBI
|
||||||
// DeleteDeadInstruction can delete the current instruction. Save BBI
|
// in case we need it.
|
||||||
// in case we need it.
|
WeakVH NextInst(BBI);
|
||||||
WeakVH NextInst(BBI);
|
|
||||||
|
DeleteDeadInstruction(SI);
|
||||||
DeleteDeadInstruction(SI);
|
|
||||||
|
if (NextInst == 0) // Next instruction deleted.
|
||||||
if (NextInst == 0) // Next instruction deleted.
|
BBI = BB.begin();
|
||||||
BBI = BB.begin();
|
else if (BBI != BB.begin()) // Revisit this instruction if possible.
|
||||||
else if (BBI != BB.begin()) // Revisit this instruction if possible.
|
--BBI;
|
||||||
--BBI;
|
NumFastStores++;
|
||||||
NumFastStores++;
|
MadeChange = true;
|
||||||
MadeChange = true;
|
continue;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -242,7 +176,7 @@ bool DSE::runOnBasicBlock(BasicBlock &BB) {
|
|||||||
// in case we need it.
|
// in case we need it.
|
||||||
WeakVH NextInst(BBI);
|
WeakVH NextInst(BBI);
|
||||||
|
|
||||||
DeleteDeadInstruction(Inst);
|
DeleteDeadInstruction(SI);
|
||||||
|
|
||||||
if (NextInst == 0) // Next instruction deleted.
|
if (NextInst == 0) // Next instruction deleted.
|
||||||
BBI = BB.begin();
|
BBI = BB.begin();
|
||||||
@@ -268,11 +202,11 @@ bool DSE::runOnBasicBlock(BasicBlock &BB) {
|
|||||||
bool DSE::handleFreeWithNonTrivialDependency(Instruction *F, MemDepResult Dep) {
|
bool DSE::handleFreeWithNonTrivialDependency(Instruction *F, MemDepResult Dep) {
|
||||||
AliasAnalysis &AA = getAnalysis<AliasAnalysis>();
|
AliasAnalysis &AA = getAnalysis<AliasAnalysis>();
|
||||||
|
|
||||||
Instruction *Dependency = Dep.getInst();
|
StoreInst *Dependency = dyn_cast_or_null<StoreInst>(Dep.getInst());
|
||||||
if (!Dependency || !doesClobberMemory(Dependency) || !isElidable(Dependency))
|
if (!Dependency || Dependency->isVolatile())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Value *DepPointer = getPointerOperand(Dependency)->getUnderlyingObject();
|
Value *DepPointer = Dependency->getPointerOperand()->getUnderlyingObject();
|
||||||
|
|
||||||
// Check for aliasing.
|
// Check for aliasing.
|
||||||
if (AA.alias(F->getOperand(1), 1, DepPointer, 1) !=
|
if (AA.alias(F->getOperand(1), 1, DepPointer, 1) !=
|
||||||
@@ -317,28 +251,39 @@ bool DSE::handleEndBlock(BasicBlock &BB) {
|
|||||||
--BBI;
|
--BBI;
|
||||||
|
|
||||||
// If we find a store whose pointer is dead.
|
// If we find a store whose pointer is dead.
|
||||||
if (doesClobberMemory(BBI)) {
|
if (StoreInst* S = dyn_cast<StoreInst>(BBI)) {
|
||||||
if (isElidable(BBI)) {
|
if (!S->isVolatile()) {
|
||||||
// See through pointer-to-pointer bitcasts
|
// See through pointer-to-pointer bitcasts
|
||||||
Value *pointerOperand = getPointerOperand(BBI)->getUnderlyingObject();
|
Value* pointerOperand = S->getPointerOperand()->getUnderlyingObject();
|
||||||
|
|
||||||
// Alloca'd pointers or byval arguments (which are functionally like
|
// Alloca'd pointers or byval arguments (which are functionally like
|
||||||
// alloca's) are valid candidates for removal.
|
// alloca's) are valid candidates for removal.
|
||||||
if (deadPointers.count(pointerOperand)) {
|
if (deadPointers.count(pointerOperand)) {
|
||||||
// DCE instructions only used to calculate that store.
|
// DCE instructions only used to calculate that store.
|
||||||
Instruction *Dead = BBI;
|
|
||||||
BBI++;
|
BBI++;
|
||||||
DeleteDeadInstruction(Dead, &deadPointers);
|
DeleteDeadInstruction(S, &deadPointers);
|
||||||
NumFastStores++;
|
NumFastStores++;
|
||||||
MadeChange = true;
|
MadeChange = true;
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Because a memcpy or memmove is also a load, we can't skip it if we
|
continue;
|
||||||
// didn't remove it.
|
}
|
||||||
if (!isa<MemTransferInst>(BBI))
|
|
||||||
|
// We can also remove memcpy's to local variables at the end of a function.
|
||||||
|
if (MemCpyInst *M = dyn_cast<MemCpyInst>(BBI)) {
|
||||||
|
Value *dest = M->getDest()->getUnderlyingObject();
|
||||||
|
|
||||||
|
if (deadPointers.count(dest)) {
|
||||||
|
BBI++;
|
||||||
|
DeleteDeadInstruction(M, &deadPointers);
|
||||||
|
NumFastOther++;
|
||||||
|
MadeChange = true;
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Because a memcpy is also a load, we can't skip it if we didn't remove
|
||||||
|
// it.
|
||||||
}
|
}
|
||||||
|
|
||||||
Value* killPointer = 0;
|
Value* killPointer = 0;
|
||||||
@@ -359,11 +304,11 @@ bool DSE::handleEndBlock(BasicBlock &BB) {
|
|||||||
killPointer = L->getPointerOperand();
|
killPointer = L->getPointerOperand();
|
||||||
} else if (VAArgInst* V = dyn_cast<VAArgInst>(BBI)) {
|
} else if (VAArgInst* V = dyn_cast<VAArgInst>(BBI)) {
|
||||||
killPointer = V->getOperand(0);
|
killPointer = V->getOperand(0);
|
||||||
} else if (isa<MemTransferInst>(BBI) &&
|
} else if (isa<MemCpyInst>(BBI) &&
|
||||||
isa<ConstantInt>(cast<MemTransferInst>(BBI)->getLength())) {
|
isa<ConstantInt>(cast<MemCpyInst>(BBI)->getLength())) {
|
||||||
killPointer = cast<MemTransferInst>(BBI)->getSource();
|
killPointer = cast<MemCpyInst>(BBI)->getSource();
|
||||||
killPointerSize = cast<ConstantInt>(
|
killPointerSize = cast<ConstantInt>(
|
||||||
cast<MemTransferInst>(BBI)->getLength())->getZExtValue();
|
cast<MemCpyInst>(BBI)->getLength())->getZExtValue();
|
||||||
} else if (AllocaInst* A = dyn_cast<AllocaInst>(BBI)) {
|
} else if (AllocaInst* A = dyn_cast<AllocaInst>(BBI)) {
|
||||||
deadPointers.erase(A);
|
deadPointers.erase(A);
|
||||||
|
|
||||||
|
@@ -1,19 +0,0 @@
|
|||||||
; RUN: opt -S -dse < %s | FileCheck %s
|
|
||||||
|
|
||||||
declare void @llvm.lifetime.end(i64, i8*)
|
|
||||||
declare void @llvm.memset.i8(i8*, i8, i8, i32)
|
|
||||||
|
|
||||||
define void @test1() {
|
|
||||||
; CHECK: @test1
|
|
||||||
%A = alloca i8
|
|
||||||
|
|
||||||
store i8 0, i8* %A ;; Written to by memset
|
|
||||||
call void @llvm.lifetime.end(i64 1, i8* %A)
|
|
||||||
; CHECK: lifetime.end
|
|
||||||
|
|
||||||
call void @llvm.memset.i8(i8* %A, i8 0, i8 -1, i32 0)
|
|
||||||
; CHECK-NOT: memset
|
|
||||||
|
|
||||||
ret void
|
|
||||||
; CHECK: ret void
|
|
||||||
}
|
|
||||||
|
@@ -1,47 +0,0 @@
|
|||||||
; RUN: opt -S -dse < %s | FileCheck %s
|
|
||||||
|
|
||||||
declare void @llvm.memcpy.i8(i8*, i8*, i8, i32)
|
|
||||||
declare void @llvm.memmove.i8(i8*, i8*, i8, i32)
|
|
||||||
declare void @llvm.memset.i8(i8*, i8, i8, i32)
|
|
||||||
|
|
||||||
define void @test1() {
|
|
||||||
; CHECK: @test1
|
|
||||||
%A = alloca i8
|
|
||||||
%B = alloca i8
|
|
||||||
|
|
||||||
store i8 0, i8* %A ;; Written to by memcpy
|
|
||||||
; CHECK-NOT: store
|
|
||||||
|
|
||||||
call void @llvm.memcpy.i8(i8* %A, i8* %B, i8 -1, i32 0)
|
|
||||||
|
|
||||||
ret void
|
|
||||||
; CHECK: ret void
|
|
||||||
}
|
|
||||||
|
|
||||||
define void @test2() {
|
|
||||||
; CHECK: @test2
|
|
||||||
%A = alloca i8
|
|
||||||
%B = alloca i8
|
|
||||||
|
|
||||||
store i8 0, i8* %A ;; Written to by memmove
|
|
||||||
; CHECK-NOT: store
|
|
||||||
|
|
||||||
call void @llvm.memmove.i8(i8* %A, i8* %B, i8 -1, i32 0)
|
|
||||||
|
|
||||||
ret void
|
|
||||||
; CHECK: ret void
|
|
||||||
}
|
|
||||||
|
|
||||||
define void @test3() {
|
|
||||||
; CHECK: @test3
|
|
||||||
%A = alloca i8
|
|
||||||
%B = alloca i8
|
|
||||||
|
|
||||||
store i8 0, i8* %A ;; Written to by memset
|
|
||||||
; CHECK-NOT: store
|
|
||||||
|
|
||||||
call void @llvm.memset.i8(i8* %A, i8 0, i8 -1, i32 0)
|
|
||||||
|
|
||||||
ret void
|
|
||||||
; CHECK: ret void
|
|
||||||
}
|
|
||||||
|
Reference in New Issue
Block a user