[cfe-commits] r126602 - in /cfe/trunk: lib/CodeGen/CGStmt.cpp test/CodeGen/switch-dce.c

Chris Lattner sabre at nondot.org
Sun Feb 27 17:02:30 PST 2011


Author: lattner
Date: Sun Feb 27 19:02:29 2011
New Revision: 126602

URL: http://llvm.org/viewvc/llvm-project?rev=126602&view=rev
Log:
make switch condition constant folding much more aggressive, handling 
compound statements and break statements.  This implements enough to 
handle PR9322 and rdar://6970405.


Modified:
    cfe/trunk/lib/CodeGen/CGStmt.cpp
    cfe/trunk/test/CodeGen/switch-dce.c

Modified: cfe/trunk/lib/CodeGen/CGStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGStmt.cpp?rev=126602&r1=126601&r2=126602&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGStmt.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGStmt.cpp Sun Feb 27 19:02:29 2011
@@ -857,6 +857,13 @@
                                             const SwitchCase *Case,
                                             bool &FoundCase,
                               llvm::SmallVectorImpl<const Stmt*> &ResultStmts) {
+  assert((!FoundCase || Case == 0) &&
+         "Can't be looking for the case if we already found it!");
+  
+  // If this is a null statement, just succeed.
+  if (S == 0)
+    return Case ? CSFC_Success : CSFC_FallThrough;
+    
   // If this is the switchcase (case 4: or default) that we're looking for, then
   // we're in business.  Just add the substatement.
   if (const SwitchCase *SC = dyn_cast<SwitchCase>(S)) {
@@ -870,12 +877,72 @@
     return CollectStatementsForCase(SC->getSubStmt(), Case, FoundCase,
                                     ResultStmts);
   }
+
+  // If we are in the live part of the code and we found our break statement,
+  // return a success!
+  if (Case == 0 && isa<BreakStmt>(S))
+    return CSFC_Success;
   
+  // If this is a switch statement, then it might contain the SwitchCase, the
+  // break, or neither.
+  if (const CompoundStmt *CS = dyn_cast<CompoundStmt>(S)) {
+    // Handle this as two cases: we might be looking for the SwitchCase (if so
+    // the skipped statements must be skippable) or we might already have it.
+    CompoundStmt::const_body_iterator I = CS->body_begin(), E = CS->body_end();
+    if (Case) {
+      // If we're looking for the case, just see if we can skip each of the
+      // substatements.
+      for (; Case && I != E; ++I) {
+        switch (CollectStatementsForCase(*I, Case, FoundCase, ResultStmts)) {
+        case CSFC_Failure: return CSFC_Failure;
+        case CSFC_Success:
+          // A successful result means that either 1) that the statement doesn't
+          // have the case and is skippable, or 2) does contain the case value
+          // and also contains the break to exit the switch.  In either case,
+          // we continue scanning the body of the compound statement to see if
+          // the rest are skippable or have the case.
+          break;
+        case CSFC_FallThrough:
+          // If we have a fallthrough condition, then we must have found the
+          // case started to include statements.  Consider the rest of the
+          // statements in the compound statement as candidates for inclusion.
+          assert(FoundCase && "Didn't find case but returned fallthrough?");
+          // We recursively found Case, so we're not looking for it anymore.
+          Case = 0;
+          break;
+        }
+      }
+    }
+
+    // If we have statements in our range, then we know that the statements are
+    // live and need to be added to the set of statements we're tracking.
+    for (; I != E; ++I) {
+      switch (CollectStatementsForCase(*I, 0, FoundCase, ResultStmts)) {
+      case CSFC_Failure: return CSFC_Failure;
+      case CSFC_FallThrough:
+        // A fallthrough result means that the statement was simple and just
+        // included in ResultStmt, keep adding them afterwards.
+        break;
+      case CSFC_Success:
+        // A successful result means that we found the break statement and
+        // stopped statement inclusion.  We just ensure that any leftover stmts
+        // are skippable and return success ourselves.
+        for (++I; I != E; ++I)
+          if (CodeGenFunction::ContainsLabel(*I, true))
+            return CSFC_Failure;
+        return CSFC_Success;
+      }      
+    }
+    
+    return Case ? CSFC_Success : CSFC_FallThrough;
+  }
+
   // Okay, this is some other statement that we don't handle explicitly, like a
   // for statement or increment etc.  If we are skipping over this statement,
   // just verify it doesn't have labels, which would make it invalid to elide.
   if (Case) {
-    if (CodeGenFunction::ContainsLabel(S, true))
+    if (CodeGenFunction::ContainsLabel(S, true) ||
+        isa<DeclStmt>(S))
       return CSFC_Failure;
     return CSFC_Success;
   }

Modified: cfe/trunk/test/CodeGen/switch-dce.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/switch-dce.c?rev=126602&r1=126601&r2=126602&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/switch-dce.c (original)
+++ cfe/trunk/test/CodeGen/switch-dce.c Sun Feb 27 19:02:29 2011
@@ -1,18 +1,169 @@
 // RUN: %clang_cc1 -triple i386-unknown-unknown -O0 %s -emit-llvm -o - | FileCheck %s
 
+// PR9322 and rdar://6970405
+
 // CHECK: @test1
 // CHECK-NOT: switch
+// CHECK-NOT: @dead
 // CHECK: add nsw i32 {{.*}}, 1
 // CHECK-NOT: switch
-// CHECK-NOT: add nsw i32
+// CHECK-NOT: @dead
 // CHECK: ret void
+int i;
+void dead();
+
 void test1() {
-  int i;
   switch (1)
     case 1:
       ++i;
 
   switch (0)
     case 1:
-      i+=2;
+      dead();
 } 
+
+
+// CHECK: @test2
+// CHECK-NOT: switch
+// CHECK-NOT: @dead
+// CHECK: add nsw i32 {{.*}}, 2
+// CHECK-NOT: switch
+// CHECK-NOT: @dead
+// CHECK: ret void
+void test2() {
+  switch (4) {
+  case 1:
+    dead();
+    break;
+  case 4:
+    i += 2;
+    // Fall off the end of the switch.
+  } 
+}
+
+
+// CHECK: @test3
+// CHECK-NOT: switch
+// CHECK-NOT: @dead
+// CHECK: add nsw i32 {{.*}}, 2
+// CHECK-NOT: switch
+// CHECK-NOT: @dead
+// CHECK: ret void
+void test3() {
+  switch (4) {
+  case 1:
+    dead();
+    break;
+  case 4: {
+    i += 2;
+    break;
+  }
+  } 
+}
+
+// CHECK: @test4
+// CHECK-NOT: switch
+// CHECK-NOT: @dead
+// CHECK: add nsw i32 {{.*}}, 2
+// CHECK-NOT: switch
+// CHECK-NOT: @dead
+// CHECK: ret void
+void test4() {
+  switch (4) {
+    case 1:
+      dead();
+      break;
+    default: {
+      i += 2;
+      break;
+    }
+  } 
+}
+
+// This shouldn't crash codegen, but we don't have to optimize out the switch
+// in this case.
+void test5() {
+  switch (1) {
+    int x;  // eliding var decl?
+    case 1:
+      x = 4;
+      break;
+  } 
+}
+
+// CHECK: @test6
+// CHECK-NOT: switch
+// CHECK-NOT: @dead
+// CHECK: ret void
+void test6() {
+  // Neither case is reachable.
+  switch (40) {
+  case 1:
+   dead();
+    break;
+  case 4: {
+    dead();
+    break;
+  }
+  } 
+}
+
+// CHECK: @test7
+// CHECK-NOT: switch
+// CHECK-NOT: @dead
+// CHECK: add nsw i32
+// CHECK-NOT: switch
+// CHECK-NOT: @dead
+// CHECK: ret void
+void test7() {
+  switch (4) {
+  case 1:
+      dead();
+    break;
+    {
+      case 4:   // crazy brace scenario
+        ++i;
+    }
+    break;
+  } 
+}
+
+// CHECK: @test8
+// CHECK-NOT: switch
+// CHECK-NOT: @dead
+// CHECK: add nsw i32
+// CHECK-NOT: switch
+// CHECK-NOT: @dead
+// CHECK: ret void
+void test8() {
+  switch (4) {
+  case 1:
+    dead();
+    break;
+  case 4:
+    ++i;
+    // Fall off the end of the switch.
+  } 
+}
+
+// CHECK: @test9
+// CHECK-NOT: switch
+// CHECK-NOT: @dead
+// CHECK: add nsw i32
+// CHECK: add nsw i32
+// CHECK-NOT: switch
+// CHECK-NOT: @dead
+// CHECK: ret void
+void test9(int i) {
+  switch (1) {
+  case 5:
+    dead();
+  case 1:
+    ++i;
+    // Fall through is fine.
+  case 4:
+    ++i;
+    break;
+  } 
+}
+





More information about the cfe-commits mailing list