]> granicus.if.org Git - clang/commitdiff
implement rdar://9289524 - case followed immediately by break results in empty IR...
authorChris Lattner <sabre@nondot.org>
Sun, 17 Apr 2011 00:54:30 +0000 (00:54 +0000)
committerChris Lattner <sabre@nondot.org>
Sun, 17 Apr 2011 00:54:30 +0000 (00:54 +0000)
a -O0 code quality issue.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@129652 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGCleanup.cpp
lib/CodeGen/CGStmt.cpp
lib/CodeGen/CodeGenFunction.h
test/CodeGen/switch-dce.c

index 1d7901a2db4cd1b796762b929f5bc56fee71b402..41ecd81117900feded2872da3e2507300d51c43e 100644 (file)
@@ -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.
index 7a1ce19b07cc401c419e1897b79d41d786d1ff20..b8b2cd9f3e76c97a735eb8c624751707d5d23aa1 100644 (file)
@@ -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());
index fa86f056adf8da5f2ab4de8df2b3fd80d13af223..913b5dfa7d59df0f422839be90a0e085db1a2392 100644 (file)
@@ -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
index a03c4001d3d54208413caed6dc55f87b9c62de5d..07a5eba23607f588e1ffcae2bed5d6df15c96357 100644 (file)
@@ -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;
+  }
+}