]> granicus.if.org Git - clang/commitdiff
add a special case for codegen that improves the case where we have
authorChris Lattner <sabre@nondot.org>
Wed, 4 Mar 2009 04:46:18 +0000 (04:46 +0000)
committerChris Lattner <sabre@nondot.org>
Wed, 4 Mar 2009 04:46:18 +0000 (04:46 +0000)
multiple sequential cases to a) not create tons of fall-through basic blocks
and b) not recurse deeply.  This fixes codegen on 100K deep cases, and improves
codegen on moderate cases from this:

        switch i32 %tmp, label %sw.epilog [
                i32 1000, label %sw.bb
                i32 1001, label %sw.bb1
                i32 1002, label %sw.bb2
                i32 1003, label %sw.bb3
                i32 1004, label %sw.bb4
...
sw.bb:          ; preds = %entry
        br label %sw.bb1

sw.bb1:         ; preds = %entry, %sw.bb
        br label %sw.bb2

sw.bb2:         ; preds = %entry, %sw.bb1
        br label %sw.bb3

sw.bb3:         ; preds = %entry, %sw.bb2
        br label %sw.bb4

to:

        switch i32 %tmp, label %sw.epilog [
                i32 1000, label %sw.bb
                i32 1001, label %sw.bb
                i32 1002, label %sw.bb
                i32 1003, label %sw.bb
                i32 1004, label %sw.bb
sw.bb:  ;; many preds

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

lib/CodeGen/CGStmt.cpp

index cbd8a897bd203fa3955e2a051d053dbe79fa3526..839ba671b92cce833fa7667968d279800d507891 100644 (file)
@@ -592,7 +592,30 @@ void CodeGenFunction::EmitCaseStmt(const CaseStmt &S) {
   llvm::BasicBlock *CaseDest = Builder.GetInsertBlock();
   llvm::APSInt CaseVal = S.getLHS()->EvaluateAsInt(getContext());
   SwitchInsn->addCase(llvm::ConstantInt::get(CaseVal), CaseDest);
-  EmitStmt(S.getSubStmt());
+  
+  // Recursively emitting the statement is acceptable, but is not wonderful for
+  // code where we have many case statements nested together, i.e.:
+  //  case 1:
+  //    case 2:
+  //      case 3: etc.
+  // Handling this recursively will create a new block for each case statement
+  // that falls through to the next case which is IR intensive.  It also causes
+  // deep recursion which can run into stack depth limitations.  Handle
+  // sequential non-range case statements specially.
+  const CaseStmt *CurCase = &S;
+  const CaseStmt *NextCase = dyn_cast<CaseStmt>(S.getSubStmt());
+
+  // Otherwise, iteratively add consequtive cases to this switch stmt.
+  while (NextCase && NextCase->getRHS() == 0) {
+    CurCase = NextCase;
+    CaseVal = CurCase->getLHS()->EvaluateAsInt(getContext());
+    SwitchInsn->addCase(llvm::ConstantInt::get(CaseVal), CaseDest);
+
+    NextCase = dyn_cast<CaseStmt>(CurCase->getSubStmt());
+  }
+  
+  // Normal default recursion for non-cases.
+  EmitStmt(CurCase->getSubStmt());
 }
 
 void CodeGenFunction::EmitDefaultStmt(const DefaultStmt &S) {