[cfe-commits] r149190 - in /cfe/trunk: lib/CodeGen/CGCall.cpp test/CodeGenCXX/arm.cpp test/CodeGenObjC/arc.m
John McCall
rjmccall at apple.com
Sat Jan 28 18:35:03 PST 2012
Author: rjmccall
Date: Sat Jan 28 20:35:02 2012
New Revision: 149190
URL: http://llvm.org/viewvc/llvm-project?rev=149190&view=rev
Log:
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.
Modified:
cfe/trunk/lib/CodeGen/CGCall.cpp
cfe/trunk/test/CodeGenCXX/arm.cpp
cfe/trunk/test/CodeGenObjC/arc.m
Modified: cfe/trunk/lib/CodeGen/CGCall.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCall.cpp?rev=149190&r1=149189&r2=149190&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCall.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGCall.cpp Sat Jan 28 20:35:02 2012
@@ -1189,6 +1189,44 @@
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 @@
// 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 @@
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;
Modified: cfe/trunk/test/CodeGenCXX/arm.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/arm.cpp?rev=149190&r1=149189&r2=149190&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/arm.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/arm.cpp Sat Jan 28 20:35:02 2012
@@ -45,24 +45,18 @@
}
// 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.
Modified: cfe/trunk/test/CodeGenObjC/arc.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/arc.m?rev=149190&r1=149189&r2=149190&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenObjC/arc.m (original)
+++ cfe/trunk/test/CodeGenObjC/arc.m Sat Jan 28 20:35:02 2012
@@ -13,23 +13,20 @@
// 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 @@
@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 @@
// 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 @@
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 @@
// 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 @@
// 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 @@
// 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 @@
// 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 @@
}
- (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 @@
// 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 @@
// 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;
}
More information about the cfe-commits
mailing list