forked from OSchip/llvm-project
[SCCP] Zap multiple return values.
We can replace the return values with undef if we replaced all the call uses with a constant/undef. Differential Revision: https://reviews.llvm.org/D22336 llvm-svn: 276174
This commit is contained in:
parent
a088bce959
commit
15ff2d6d0c
|
@ -300,6 +300,12 @@ public:
|
|||
return TrackedGlobals;
|
||||
}
|
||||
|
||||
/// getMRVFunctionsTracked - Get the set of functions which return multiple
|
||||
/// values tracked by the pass.
|
||||
const SmallPtrSet<Function *, 16> getMRVFunctionsTracked() {
|
||||
return MRVFunctionsTracked;
|
||||
}
|
||||
|
||||
void markOverdefined(Value *V) {
|
||||
assert(!V->getType()->isStructTy() &&
|
||||
"structs should use markAnythingOverdefined");
|
||||
|
@ -316,6 +322,20 @@ public:
|
|||
markOverdefined(V);
|
||||
}
|
||||
|
||||
// isStructLatticeConstant - Return true if all the lattice values
|
||||
// corresponding to elements of the structure are not overdefined,
|
||||
// false otherwise.
|
||||
bool isStructLatticeConstant(Function *F, StructType *STy) {
|
||||
for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
|
||||
const auto &It = TrackedMultipleRetVals.find(std::make_pair(F, i));
|
||||
assert(It != TrackedMultipleRetVals.end());
|
||||
LatticeVal LV = It->second;
|
||||
if (LV.isOverdefined())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
// pushToWorkList - Helper for markConstant/markForcedConstant
|
||||
void pushToWorkList(LatticeVal &IV, Value *V) {
|
||||
|
@ -1690,6 +1710,19 @@ static bool AddressIsTaken(const GlobalValue *GV) {
|
|||
return false;
|
||||
}
|
||||
|
||||
static void findReturnsToZap(Function &F,
|
||||
SmallPtrSet<Function *, 32> &AddressTakenFunctions,
|
||||
SmallVector<ReturnInst *, 8> &ReturnsToZap) {
|
||||
// We can only do this if we know that nothing else can call the function.
|
||||
if (!F.hasLocalLinkage() || AddressTakenFunctions.count(&F))
|
||||
return;
|
||||
|
||||
for (BasicBlock &BB : F)
|
||||
if (ReturnInst *RI = dyn_cast<ReturnInst>(BB.getTerminator()))
|
||||
if (!isa<UndefValue>(RI->getOperand(0)))
|
||||
ReturnsToZap.push_back(RI);
|
||||
}
|
||||
|
||||
static bool runIPSCCP(Module &M, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI) {
|
||||
SCCPSolver Solver(DL, TLI);
|
||||
|
@ -1866,21 +1899,20 @@ static bool runIPSCCP(Module &M, const DataLayout &DL,
|
|||
// whether other functions are optimizable.
|
||||
SmallVector<ReturnInst*, 8> ReturnsToZap;
|
||||
|
||||
// TODO: Process multiple value ret instructions also.
|
||||
const DenseMap<Function*, LatticeVal> &RV = Solver.getTrackedRetVals();
|
||||
for (const auto &I : RV) {
|
||||
Function *F = I.first;
|
||||
if (I.second.isOverdefined() || F->getReturnType()->isVoidTy())
|
||||
continue;
|
||||
findReturnsToZap(*F, AddressTakenFunctions, ReturnsToZap);
|
||||
}
|
||||
|
||||
// We can only do this if we know that nothing else can call the function.
|
||||
if (!F->hasLocalLinkage() || AddressTakenFunctions.count(F))
|
||||
continue;
|
||||
|
||||
for (BasicBlock &BB : *F)
|
||||
if (ReturnInst *RI = dyn_cast<ReturnInst>(BB.getTerminator()))
|
||||
if (!isa<UndefValue>(RI->getOperand(0)))
|
||||
ReturnsToZap.push_back(RI);
|
||||
for (const auto &F : Solver.getMRVFunctionsTracked()) {
|
||||
assert(F->getReturnType()->isStructTy() &&
|
||||
"The return type should be a struct");
|
||||
StructType *STy = cast<StructType>(F->getReturnType());
|
||||
if (Solver.isStructLatticeConstant(F, STy))
|
||||
findReturnsToZap(*F, AddressTakenFunctions, ReturnsToZap);
|
||||
}
|
||||
|
||||
// Zap all returns which we've identified as zap to change.
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
; RUN: opt -ipsccp < %s -S | FileCheck %s
|
||||
|
||||
define internal {i32, i32} @identity(i32 %patatino) {
|
||||
%foo = insertvalue {i32, i32} {i32 1, i32 undef}, i32 %patatino, 1
|
||||
ret {i32, i32} %foo
|
||||
}
|
||||
|
||||
; Check that the return value is not transformed to undef
|
||||
; CHECK: define internal { i32, i32 } @identity(i32 %patatino) {
|
||||
; CHECK-NEXT: %foo = insertvalue { i32, i32 } { i32 1, i32 undef }, i32 %patatino, 1
|
||||
; CHECK-NEXT: ret { i32, i32 } %foo
|
||||
; CHECK-NEXT: }
|
||||
|
||||
|
||||
define {i32, i32} @caller(i32 %pat) {
|
||||
%S1 = call {i32, i32} @identity(i32 %pat)
|
||||
ret {i32, i32} %S1
|
||||
}
|
||||
|
||||
; Check that we don't invent values and propagate them.
|
||||
; CHECK: define { i32, i32 } @caller(i32 %pat) {
|
||||
; CHECK-NEXT: %S1 = call { i32, i32 } @identity(i32 %pat)
|
||||
; CHECK-NEXT: ret { i32, i32 } %S1
|
||||
; CHECK-NEXT: }
|
|
@ -83,7 +83,7 @@ define internal {i64,i64} @test4a() {
|
|||
}
|
||||
|
||||
; CHECK-LABEL: define internal { i64, i64 } @test4a(
|
||||
; CHECK-NEXT: ret { i64, i64 } { i64 5, i64 4 }
|
||||
; CHECK-NEXT: ret { i64, i64 } undef
|
||||
; CHECK-NEXT: }
|
||||
|
||||
define i64 @test4b() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
|
||||
|
@ -167,7 +167,7 @@ define internal %T @test7a(i32 %A) {
|
|||
%mrv1 = insertvalue %T %mrv0, i32 %A, 1
|
||||
ret %T %mrv1
|
||||
; CHECK-LABEL: @test7a(
|
||||
; CHECK-NEXT: ret %T { i32 18, i32 17 }
|
||||
; CHECK-NEXT: ret %T undef
|
||||
}
|
||||
|
||||
define i32 @test7b() {
|
||||
|
|
Loading…
Reference in New Issue