[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