forked from OSchip/llvm-project
Get a little bit smarter about killing off the ReturnValue alloca
in the presence of straight-line cleanups. This is a simple but important case, particularly for ARC. llvm-svn: 149190
This commit is contained in:
parent
198236edae
commit
6e1c012385
|
@ -1189,6 +1189,44 @@ static llvm::Value *emitAutoreleaseOfResult(CodeGenFunction &CGF,
|
|||
return CGF.EmitARCAutoreleaseReturnValue(result);
|
||||
}
|
||||
|
||||
/// Heuristically search for a dominating store to the return-value slot.
|
||||
static llvm::StoreInst *findDominatingStoreToReturnValue(CodeGenFunction &CGF) {
|
||||
// If there are multiple uses of the return-value slot, just check
|
||||
// for something immediately preceding the IP. Sometimes this can
|
||||
// happen with how we generate implicit-returns; it can also happen
|
||||
// with noreturn cleanups.
|
||||
if (!CGF.ReturnValue->hasOneUse()) {
|
||||
llvm::BasicBlock *IP = CGF.Builder.GetInsertBlock();
|
||||
if (IP->empty()) return 0;
|
||||
llvm::StoreInst *store = dyn_cast<llvm::StoreInst>(&IP->back());
|
||||
if (!store) return 0;
|
||||
if (store->getPointerOperand() != CGF.ReturnValue) return 0;
|
||||
assert(!store->isAtomic() && !store->isVolatile()); // see below
|
||||
return store;
|
||||
}
|
||||
|
||||
llvm::StoreInst *store =
|
||||
dyn_cast<llvm::StoreInst>(CGF.ReturnValue->use_back());
|
||||
if (!store) return 0;
|
||||
|
||||
// These aren't actually possible for non-coerced returns, and we
|
||||
// only care about non-coerced returns on this code path.
|
||||
assert(!store->isAtomic() && !store->isVolatile());
|
||||
|
||||
// Now do a first-and-dirty dominance check: just walk up the
|
||||
// single-predecessors chain from the current insertion point.
|
||||
llvm::BasicBlock *StoreBB = store->getParent();
|
||||
llvm::BasicBlock *IP = CGF.Builder.GetInsertBlock();
|
||||
while (IP != StoreBB) {
|
||||
if (!(IP = IP->getSinglePredecessor()))
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Okay, the store's basic block dominates the insertion point; we
|
||||
// can do our thing.
|
||||
return store;
|
||||
}
|
||||
|
||||
void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI) {
|
||||
// Functions with no result always return void.
|
||||
if (ReturnValue == 0) {
|
||||
|
@ -1223,16 +1261,9 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI) {
|
|||
// The internal return value temp always will have pointer-to-return-type
|
||||
// type, just do a load.
|
||||
|
||||
// If the instruction right before the insertion point is a store to the
|
||||
// return value, we can elide the load, zap the store, and usually zap the
|
||||
// alloca.
|
||||
llvm::BasicBlock *InsertBB = Builder.GetInsertBlock();
|
||||
llvm::StoreInst *SI = 0;
|
||||
if (InsertBB->empty() ||
|
||||
!(SI = dyn_cast<llvm::StoreInst>(&InsertBB->back())) ||
|
||||
SI->getPointerOperand() != ReturnValue || SI->isVolatile()) {
|
||||
RV = Builder.CreateLoad(ReturnValue);
|
||||
} else {
|
||||
// If there is a dominating store to ReturnValue, we can elide
|
||||
// the load, zap the store, and usually zap the alloca.
|
||||
if (llvm::StoreInst *SI = findDominatingStoreToReturnValue(*this)) {
|
||||
// Get the stored value and nuke the now-dead store.
|
||||
RetDbgLoc = SI->getDebugLoc();
|
||||
RV = SI->getValueOperand();
|
||||
|
@ -1243,6 +1274,10 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI) {
|
|||
cast<llvm::AllocaInst>(ReturnValue)->eraseFromParent();
|
||||
ReturnValue = 0;
|
||||
}
|
||||
|
||||
// Otherwise, we have to do a simple load.
|
||||
} else {
|
||||
RV = Builder.CreateLoad(ReturnValue);
|
||||
}
|
||||
} else {
|
||||
llvm::Value *V = ReturnValue;
|
||||
|
|
|
@ -45,24 +45,18 @@ namespace test1 {
|
|||
}
|
||||
|
||||
// CHECK: define linkonce_odr [[A]]* @_ZN5test11AC1Ei([[A]]* %this, i32 %i) unnamed_addr
|
||||
// CHECK: [[RET:%.*]] = alloca [[A]]*, align 4
|
||||
// CHECK: [[THIS:%.*]] = alloca [[A]]*, align 4
|
||||
// CHECK: store [[A]]* {{.*}}, [[A]]** [[THIS]]
|
||||
// CHECK: [[THIS1:%.*]] = load [[A]]** [[THIS]]
|
||||
// CHECK: store [[A]]* [[THIS1]], [[A]]** [[RET]]
|
||||
// CHECK: call [[A]]* @_ZN5test11AC2Ei(
|
||||
// CHECK: [[THIS2:%.*]] = load [[A]]** [[RET]]
|
||||
// CHECK: ret [[A]]* [[THIS2]]
|
||||
// CHECK: ret [[A]]* [[THIS1]]
|
||||
|
||||
// CHECK: define linkonce_odr [[A]]* @_ZN5test11AD1Ev([[A]]* %this) unnamed_addr
|
||||
// CHECK: [[RET:%.*]] = alloca [[A]]*, align 4
|
||||
// CHECK: [[THIS:%.*]] = alloca [[A]]*, align 4
|
||||
// CHECK: store [[A]]* {{.*}}, [[A]]** [[THIS]]
|
||||
// CHECK: [[THIS1:%.*]] = load [[A]]** [[THIS]]
|
||||
// CHECK: store [[A]]* [[THIS1]], [[A]]** [[RET]]
|
||||
// CHECK: call [[A]]* @_ZN5test11AD2Ev(
|
||||
// CHECK: [[THIS2:%.*]] = load [[A]]** [[RET]]
|
||||
// CHECK: ret [[A]]* [[THIS2]]
|
||||
// CHECK: ret [[A]]* [[THIS1]]
|
||||
}
|
||||
|
||||
// Awkward virtual cases.
|
||||
|
|
|
@ -13,23 +13,20 @@ void test0(id x) {
|
|||
|
||||
// CHECK: define i8* @test1(i8*
|
||||
id test1(id x) {
|
||||
// CHECK: [[RET:%.*]] = alloca i8*
|
||||
// CHECK-NEXT: [[X:%.*]] = alloca i8*
|
||||
// CHECK: [[X:%.*]] = alloca i8*
|
||||
// CHECK-NEXT: [[Y:%.*]] = alloca i8*
|
||||
// CHECK-NEXT: alloca i32
|
||||
// CHECK-NEXT: [[PARM:%.*]] = call i8* @objc_retain(i8* {{%.*}})
|
||||
// CHECK-NEXT: store i8* [[PARM]], i8** [[X]]
|
||||
// CHECK-NEXT: store i8* null, i8** [[Y]]
|
||||
// CHECK-NEXT: [[T0:%.*]] = load i8** [[Y]]
|
||||
// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]])
|
||||
// CHECK-NEXT: store i8* [[T1]], i8** [[RET]]
|
||||
// CHECK-NEXT: [[RET:%.*]] = call i8* @objc_retain(i8* [[T0]])
|
||||
// CHECK-NEXT: store i32
|
||||
// CHECK-NEXT: [[T0:%.*]] = load i8** [[Y]]
|
||||
// CHECK-NEXT: call void @objc_release(i8* [[T0]])
|
||||
// CHECK-NEXT: [[T1:%.*]] = load i8** [[X]]
|
||||
// CHECK-NEXT: call void @objc_release(i8* [[T1]])
|
||||
// CHECK-NEXT: [[T0:%.*]] = load i8** [[RET]]
|
||||
// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_autoreleaseReturnValue(i8* [[T0]])
|
||||
// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_autoreleaseReturnValue(i8* [[RET]])
|
||||
// CHECK-NEXT: ret i8* [[T1]]
|
||||
id y;
|
||||
return y;
|
||||
|
@ -636,8 +633,7 @@ void test22(_Bool cond) {
|
|||
@implementation Test27
|
||||
- (id) init { return self; }
|
||||
// CHECK: define internal i8* @"\01-[Test27 init]"
|
||||
// CHECK: [[RET:%.*]] = alloca i8*,
|
||||
// CHECK-NEXT: [[SELF:%.*]] = alloca [[TEST27:%.*]]*,
|
||||
// CHECK: [[SELF:%.*]] = alloca [[TEST27:%.*]]*,
|
||||
// CHECK-NEXT: [[CMD:%.*]] = alloca i8*,
|
||||
// CHECK-NEXT: [[DEST:%.*]] = alloca i32
|
||||
// CHECK-NEXT: store [[TEST27]]* {{%.*}}, [[TEST27]]** [[SELF]]
|
||||
|
@ -646,14 +642,12 @@ void test22(_Bool cond) {
|
|||
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST27]]* [[T0]] to i8*
|
||||
// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]])
|
||||
// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]]
|
||||
// CHECK-NEXT: [[T2:%.*]] = bitcast
|
||||
// CHECK-NEXT: store i8* [[T2]], i8** [[RET]]
|
||||
// CHECK-NEXT: [[RET:%.*]] = bitcast
|
||||
// CHECK-NEXT: store i32 {{[0-9]+}}, i32* [[DEST]]
|
||||
// CHECK-NEXT: [[T0:%.*]] = load [[TEST27]]** [[SELF]]
|
||||
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST27]]* [[T0]] to i8*
|
||||
// CHECK-NEXT: call void @objc_release(i8* [[T1]])
|
||||
// CHECK-NEXT: [[T0:%.*]] = load i8** [[RET]]
|
||||
// CHECK-NEXT: ret i8* [[T0]]
|
||||
// CHECK-NEXT: ret i8* [[RET]]
|
||||
|
||||
@end
|
||||
|
||||
|
@ -684,8 +678,7 @@ void test22(_Bool cond) {
|
|||
static id _test29_allocator = 0;
|
||||
- (id) init {
|
||||
// CHECK: define internal i8* @"\01-[Test29 init]"([[TEST29:%.*]]* {{%.*}},
|
||||
// CHECK: [[RET:%.*]] = alloca i8*, align 8
|
||||
// CHECK-NEXT: [[SELF:%.*]] = alloca [[TEST29]]*, align 8
|
||||
// CHECK: [[SELF:%.*]] = alloca [[TEST29]]*, align 8
|
||||
// CHECK-NEXT: [[CMD:%.*]] = alloca i8*, align 8
|
||||
// CHECK-NEXT: [[CLEANUP:%.*]] = alloca i32
|
||||
// CHECK-NEXT: store [[TEST29]]* {{%.*}}, [[TEST29]]** [[SELF]]
|
||||
|
@ -715,8 +708,7 @@ static id _test29_allocator = 0;
|
|||
// CHECK-NEXT: [[CALL:%.*]] = bitcast
|
||||
// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[CALL]]) nounwind
|
||||
// CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]]
|
||||
// CHECK-NEXT: [[T1:%.*]] = bitcast
|
||||
// CHECK-NEXT: store i8* [[T1]], i8** [[RET]]
|
||||
// CHECK-NEXT: [[RET:%.*]] = bitcast
|
||||
// CHECK-NEXT: store i32 1, i32* [[CLEANUP]]
|
||||
|
||||
// Cleanup.
|
||||
|
@ -725,14 +717,12 @@ static id _test29_allocator = 0;
|
|||
// CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind, !clang.imprecise_release
|
||||
|
||||
// Return.
|
||||
// CHECK-NEXT: [[T0:%.*]] = load i8** [[RET]]
|
||||
// CHECK-NEXT: ret i8* [[T0]]
|
||||
// CHECK-NEXT: ret i8* [[RET]]
|
||||
return [self initWithAllocator: _test29_allocator];
|
||||
}
|
||||
- (id) initWithAllocator: (id) allocator {
|
||||
// CHECK: define internal i8* @"\01-[Test29 initWithAllocator:]"(
|
||||
// CHECK: [[RET:%.*]] = alloca i8*, align 8
|
||||
// CHECK-NEXT: [[SELF:%.*]] = alloca [[TEST29]]*, align 8
|
||||
// CHECK: [[SELF:%.*]] = alloca [[TEST29]]*, align 8
|
||||
// CHECK-NEXT: [[CMD:%.*]] = alloca i8*, align 8
|
||||
// CHECK-NEXT: [[ALLOCATOR:%.*]] = alloca i8*, align 8
|
||||
// CHECK-NEXT: alloca
|
||||
|
@ -774,8 +764,7 @@ static id _test29_allocator = 0;
|
|||
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST29]]* [[T0]] to i8*
|
||||
// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]]) nounwind
|
||||
// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]]
|
||||
// CHECK-NEXT: [[T2:%.*]] = bitcast
|
||||
// CHECK-NEXT: store i8* [[T2]], i8** [[RET]]
|
||||
// CHECK-NEXT: [[RET:%.*]] = bitcast
|
||||
// CHECK-NEXT: store i32 1, i32* [[CLEANUP]]
|
||||
|
||||
// Cleanup.
|
||||
|
@ -787,8 +776,7 @@ static id _test29_allocator = 0;
|
|||
// CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind, !clang.imprecise_release
|
||||
|
||||
// Return.
|
||||
// CHECK-NEXT: [[T0:%.*]] = load i8** [[RET]]
|
||||
// CHECK-NEXT: ret i8* [[T0]]
|
||||
// CHECK-NEXT: ret i8* [[RET]]
|
||||
self = [super initWithAllocator: allocator];
|
||||
return self;
|
||||
}
|
||||
|
@ -804,8 +792,7 @@ char *helper;
|
|||
}
|
||||
- (id) init {
|
||||
// CHECK: define internal i8* @"\01-[Test30 init]"([[TEST30:%.*]]* {{%.*}},
|
||||
// CHECK: [[RET:%.*]] = alloca i8*
|
||||
// CHECK-NEXT: [[SELF:%.*]] = alloca [[TEST30]]*
|
||||
// CHECK: [[RET:%.*]] = alloca [[TEST30]]*
|
||||
// CHECK-NEXT: alloca i8*
|
||||
// CHECK-NEXT: alloca i32
|
||||
// CHECK-NEXT: store [[TEST30]]* {{%.*}}, [[TEST30]]** [[SELF]]
|
||||
|
@ -834,8 +821,7 @@ char *helper;
|
|||
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST30]]* [[T0]] to i8*
|
||||
// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]])
|
||||
// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]]
|
||||
// CHECK-NEXT: [[T2:%.*]] = bitcast
|
||||
// CHECK-NEXT: store i8* [[T2]], i8** [[RET]]
|
||||
// CHECK-NEXT: [[RET:%.*]] = bitcast
|
||||
// CHECK-NEXT: store i32 1
|
||||
|
||||
// Cleanup.
|
||||
|
@ -844,8 +830,7 @@ char *helper;
|
|||
// CHECK-NEXT: call void @objc_release(i8* [[T1]])
|
||||
|
||||
// Epilogue.
|
||||
// CHECK-NEXT: [[T0:%.*]] = load i8** [[RET]]
|
||||
// CHECK-NEXT: ret i8* [[T0]]
|
||||
// CHECK-NEXT: ret i8* [[RET]]
|
||||
self->helper = [self initHelper];
|
||||
return self;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue