[cfe-commits] r42766 - in /cfe/trunk: CodeGen/CGStmt.cpp CodeGen/CodeGenFunction.cpp CodeGen/CodeGenFunction.h test/CodeGen/switch.c

Devang Patel dpatel at apple.com
Mon Oct 8 13:57:48 PDT 2007


Author: dpatel
Date: Mon Oct  8 15:57:48 2007
New Revision: 42766

URL: http://llvm.org/viewvc/llvm-project?rev=42766&view=rev
Log:
Code gen case statement ranges.

Modified:
    cfe/trunk/CodeGen/CGStmt.cpp
    cfe/trunk/CodeGen/CodeGenFunction.cpp
    cfe/trunk/CodeGen/CodeGenFunction.h
    cfe/trunk/test/CodeGen/switch.c

Modified: cfe/trunk/CodeGen/CGStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/CodeGen/CGStmt.cpp?rev=42766&r1=42765&r2=42766&view=diff

==============================================================================
--- cfe/trunk/CodeGen/CGStmt.cpp (original)
+++ cfe/trunk/CodeGen/CGStmt.cpp Mon Oct  8 15:57:48 2007
@@ -354,23 +354,73 @@
   EmitBlock(new llvm::BasicBlock());
 }
 
-void CodeGenFunction::EmitCaseStmt(const CaseStmt &S) {
-  StartBlock("sw.bb");
-  llvm::BasicBlock *CaseDest = Builder.GetInsertBlock();
-  llvm::ConstantInt *LV = cast<llvm::ConstantInt>(EmitScalarExpr(S.getLHS()));
-  SwitchInsn->addCase(LV, CaseDest);
-  if (const Expr *R = S.getRHS()) {
-    llvm::ConstantInt *RV = cast<llvm::ConstantInt>(EmitScalarExpr(R));
-    llvm::APInt LHS = LV->getValue();
-    llvm::APInt RHS = RV->getValue();
+/// EmitCaseStmtRange - If case statement range is not too big then
+/// add multiple cases to switch instruction, one for each value within
+/// the range. If range is too big then emit "if" condition check.
+void CodeGenFunction::EmitCaseStmtRange(const CaseStmt &S) {
+  assert (S.getRHS() && "Unexpected RHS value in CaseStmt");
+
+  const Expr *L = S.getLHS();
+  const Expr *R = S.getRHS();
+  llvm::ConstantInt *LV = cast<llvm::ConstantInt>(EmitScalarExpr(L));
+  llvm::ConstantInt *RV = cast<llvm::ConstantInt>(EmitScalarExpr(R));
+  llvm::APInt LHS = LV->getValue();
+  llvm::APInt RHS = RV->getValue();
+
+  llvm::APInt Range = RHS - LHS;
+  if (Range.ult(llvm::APInt(Range.getBitWidth(), 64))) {
+    // Range is small enough to add multiple switch instruction cases.
+    StartBlock("sw.bb");
+    llvm::BasicBlock *CaseDest = Builder.GetInsertBlock();
+    SwitchInsn->addCase(LV, CaseDest);
     LHS++;
     while (LHS != RHS) {
       SwitchInsn->addCase(llvm::ConstantInt::get(LHS), CaseDest);
       LHS++;
     }
-    SwitchInsn->addCase(llvm::ConstantInt::get(LHS), CaseDest);
-  }
+    SwitchInsn->addCase(RV, CaseDest);
+    EmitStmt(S.getSubStmt());
+    return;
+  } 
+    
+  // The range is too big. Emit "if" condition.
+  llvm::BasicBlock *FalseDest = NULL;
+  llvm::BasicBlock *CaseDest = new llvm::BasicBlock("sw.bb");
+
+  // If we have already seen one case statement range for this switch
+  // instruction then piggy-back otherwise use default block as false
+  // destination.
+  if (CaseRangeBlock)
+    FalseDest = CaseRangeBlock;
+  else 
+    FalseDest = SwitchInsn->getDefaultDest();
+
+  // Start new block to hold case statement range check instructions.
+  StartBlock("case.range");
+  CaseRangeBlock = Builder.GetInsertBlock();
+
+  // Emit range check.
+  llvm::Value *Diff = 
+    Builder.CreateSub(SwitchInsn->getCondition(), LV, "tmp");
+  llvm::Value *Cond = 
+    Builder.CreateICmpULE(Diff, llvm::ConstantInt::get(Range), "tmp");
+  Builder.CreateCondBr(Cond, CaseDest, FalseDest);
 
+  // Now emit case statement body.
+  EmitBlock(CaseDest);
+  EmitStmt(S.getSubStmt());
+}
+
+void CodeGenFunction::EmitCaseStmt(const CaseStmt &S) {
+  if (S.getRHS()) {
+    EmitCaseStmtRange(S);
+    return;
+  }
+    
+  StartBlock("sw.bb");
+  llvm::BasicBlock *CaseDest = Builder.GetInsertBlock();
+  llvm::ConstantInt *LV = cast<llvm::ConstantInt>(EmitScalarExpr(S.getLHS()));
+  SwitchInsn->addCase(LV, CaseDest);
   EmitStmt(S.getSubStmt());
 }
 
@@ -386,6 +436,8 @@
 
   // Handle nested switch statements.
   llvm::SwitchInst *SavedSwitchInsn = SwitchInsn;
+  llvm::BasicBlock *SavedCRBlock = CaseRangeBlock;
+  CaseRangeBlock = NULL;
 
   // Create basic block to hold stuff that comes after switch statement.
   // Initially use it to hold DefaultStmt.
@@ -403,6 +455,12 @@
   EmitStmt(S.getBody());
   BreakContinueStack.pop_back();
 
+  // If one or more case statement range is seen then use CaseRangeBlock
+  // as the default block. False edge of CaseRangeBlock will lead to 
+  // original default block.
+  if (CaseRangeBlock)
+    SwitchInsn->setSuccessor(0, CaseRangeBlock);
+  
   // Prune insert block if it is dummy.
   llvm::BasicBlock *BB = Builder.GetInsertBlock();
   if (isDummyBlock(BB))
@@ -411,4 +469,5 @@
   // Place NextBlock as the new insert point.
   Builder.SetInsertPoint(NextBlock);
   SwitchInsn = SavedSwitchInsn;
+  CaseRangeBlock = SavedCRBlock;
 }

Modified: cfe/trunk/CodeGen/CodeGenFunction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/CodeGen/CodeGenFunction.cpp?rev=42766&r1=42765&r2=42766&view=diff

==============================================================================
--- cfe/trunk/CodeGen/CodeGenFunction.cpp (original)
+++ cfe/trunk/CodeGen/CodeGenFunction.cpp Mon Oct  8 15:57:48 2007
@@ -24,7 +24,8 @@
 using namespace CodeGen;
 
 CodeGenFunction::CodeGenFunction(CodeGenModule &cgm) 
-  : CGM(cgm), Target(CGM.getContext().Target) {}
+  : CGM(cgm), Target(CGM.getContext().Target), SwitchInsn(NULL), 
+    CaseRangeBlock(NULL) {}
 
 ASTContext &CodeGenFunction::getContext() const {
   return CGM.getContext();

Modified: cfe/trunk/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/CodeGen/CodeGenFunction.h?rev=42766&r1=42765&r2=42766&view=diff

==============================================================================
--- cfe/trunk/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/CodeGen/CodeGenFunction.h Mon Oct  8 15:57:48 2007
@@ -240,10 +240,14 @@
   }; 
   llvm::SmallVector<BreakContinue, 8> BreakContinueStack;
   
-  // SwitchInsn - This is used by EmitCaseStmt() and EmitDefaultStmt() to
-  // populate switch instruction
+  /// SwitchInsn - This is used by EmitCaseStmt() and EmitDefaultStmt() to
+  /// populate switch instruction
   llvm::SwitchInst *SwitchInsn;
 
+  /// CaseRangeBlock - This is used, while constructiong swtich instruction,
+  /// to hold "if" condition for case statement ranges.
+  llvm::BasicBlock *CaseRangeBlock;
+
 public:
   CodeGenFunction(CodeGenModule &cgm);
   
@@ -322,6 +326,7 @@
   void EmitSwitchStmt(const SwitchStmt &S);
   void EmitDefaultStmt(const DefaultStmt &S);
   void EmitCaseStmt(const CaseStmt &S);
+  void EmitCaseStmtRange(const CaseStmt &S);
 
   //===--------------------------------------------------------------------===//
   //                         LValue Expression Emission

Modified: cfe/trunk/test/CodeGen/switch.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/switch.c?rev=42766&r1=42765&r2=42766&view=diff

==============================================================================
--- cfe/trunk/test/CodeGen/switch.c (original)
+++ cfe/trunk/test/CodeGen/switch.c Mon Oct  8 15:57:48 2007
@@ -30,3 +30,35 @@
 }
 
     
+int foo3(int i) {
+  int j = 0;
+  switch (i) {
+  default:
+    j = 42; break;
+  case 111:
+    j = 111; break;
+  case 0 ... 100:
+    j = 1; break;
+  case 222:
+    j = 222; break;
+  }
+  return j;
+}
+
+
+int foo4(int i) {
+  int j = 0;
+  switch (i) {
+  case 111:
+    j = 111; break;
+  case 0 ... 100:
+    j = 1; break;
+  case 222:
+    j = 222; break;
+  default:
+    j = 42; break;
+  case 501 ... 600:
+    j = 5; break;
+  }
+  return j;
+}





More information about the cfe-commits mailing list