aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Lattner <sabre@nondot.org>2011-04-17 00:54:30 +0000
committerChris Lattner <sabre@nondot.org>2011-04-17 00:54:30 +0000
commitb11f9198111796ada02b57f62cdea92134fde9f7 (patch)
treeef962f36d01588087abb2b0701ce24cc18d1c62b
parenta5e5e0f41e1dcee4603244ccea3d3956c55c23ac (diff)
implement rdar://9289524 - case followed immediately by break results in empty IR block,
a -O0 code quality issue. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@129652 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/CodeGen/CGCleanup.cpp23
-rw-r--r--lib/CodeGen/CGStmt.cpp14
-rw-r--r--lib/CodeGen/CodeGenFunction.h5
-rw-r--r--test/CodeGen/switch-dce.c15
4 files changed, 57 insertions, 0 deletions
diff --git a/lib/CodeGen/CGCleanup.cpp b/lib/CodeGen/CGCleanup.cpp
index 1d7901a2db..41ecd81117 100644
--- a/lib/CodeGen/CGCleanup.cpp
+++ b/lib/CodeGen/CGCleanup.cpp
@@ -870,6 +870,29 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
}
}
+/// isObviouslyBranchWithoutCleanups - Return true if a branch to the
+/// specified destination obviously has no cleanups to run. 'false' is always
+/// a conservatively correct answer for this method.
+bool CodeGenFunction::isObviouslyBranchWithoutCleanups(JumpDest Dest) const {
+ assert(Dest.getScopeDepth().encloses(EHStack.stable_begin())
+ && "stale jump destination");
+
+ // Calculate the innermost active normal cleanup.
+ EHScopeStack::stable_iterator TopCleanup =
+ EHStack.getInnermostActiveNormalCleanup();
+
+ // If we're not in an active normal cleanup scope, or if the
+ // destination scope is within the innermost active normal cleanup
+ // scope, we don't need to worry about fixups.
+ if (TopCleanup == EHStack.stable_end() ||
+ TopCleanup.encloses(Dest.getScopeDepth())) // works for invalid
+ return true;
+
+ // Otherwise, we might need some cleanups.
+ return false;
+}
+
+
/// Terminate the current block by emitting a branch which might leave
/// the current cleanup-protected scope. The target scope may not yet
/// be known, in which case this will require a fixup.
diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp
index 7a1ce19b07..b8b2cd9f3e 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/lib/CodeGen/CGStmt.cpp
@@ -867,11 +867,25 @@ void CodeGenFunction::EmitCaseStmtRange(const CaseStmt &S) {
}
void CodeGenFunction::EmitCaseStmt(const CaseStmt &S) {
+ // Handle case ranges.
if (S.getRHS()) {
EmitCaseStmtRange(S);
return;
}
+ // If the body of the case is just a 'break', try to not emit an empty block.
+ if (isa<BreakStmt>(S.getSubStmt())) {
+ JumpDest Block = BreakContinueStack.back().BreakBlock;
+
+ // Only do this optimization if there are no cleanups that need emitting.
+ if (isObviouslyBranchWithoutCleanups(Block)) {
+ llvm::APSInt CaseVal = S.getLHS()->EvaluateAsInt(getContext());
+ SwitchInsn->addCase(llvm::ConstantInt::get(getLLVMContext(), CaseVal),
+ Block.getBlock());
+ return;
+ }
+ }
+
EmitBlock(createBasicBlock("sw.bb"));
llvm::BasicBlock *CaseDest = Builder.GetInsertBlock();
llvm::APSInt CaseVal = S.getLHS()->EvaluateAsInt(getContext());
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index fa86f056ad..913b5dfa7d 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -769,6 +769,11 @@ public:
/// block through the normal cleanup handling code (if any) and then
/// on to \arg Dest.
void EmitBranchThroughCleanup(JumpDest Dest);
+
+ /// isObviouslyBranchWithoutCleanups - Return true if a branch to the
+ /// specified destination obviously has no cleanups to run. 'false' is always
+ /// a conservatively correct answer for this method.
+ bool isObviouslyBranchWithoutCleanups(JumpDest Dest) const;
/// EmitBranchThroughEHCleanup - Emit a branch from the current
/// insert block through the EH cleanup handling code (if any) and
diff --git a/test/CodeGen/switch-dce.c b/test/CodeGen/switch-dce.c
index a03c4001d3..07a5eba236 100644
--- a/test/CodeGen/switch-dce.c
+++ b/test/CodeGen/switch-dce.c
@@ -216,3 +216,18 @@ void test12() {
}
}
+
+// rdar://9289524 - Check that the empty cases don't produce an empty block.
+// CHECK: @test13
+// CHECK: switch
+// CHECK: i32 42, label %sw.epilog
+// CHECK: i32 11, label %sw.epilog
+// CHECK: sw.epilog:
+// CHECK: ret void
+void test13(int x) {
+ switch (x) {
+ case 42: break; // No empty block please.
+ case 11: break; // No empty block please.
+ default: test13(42); break;
+ }
+}