diff options
author | Chris Lattner <sabre@nondot.org> | 2008-11-12 07:46:33 +0000 |
---|---|---|
committer | Chris Lattner <sabre@nondot.org> | 2008-11-12 07:46:33 +0000 |
commit | 9bc47e29dce8f095be7a6d07dbb02a5a7a112949 (patch) | |
tree | d2cb6a21700ee6cb983a889e5b6704676f5f2f40 /lib/CodeGen/CGStmt.cpp | |
parent | 32fea9d18cc3658a1b01df5ca6f2ac302625c61d (diff) |
Make emission of 'if' conditions much more sophisticated when we
have a condition that is an &&/||. Before we used to compile things like this:
int test() {
if (x && y) foo(); else bar();
}
into:
%0 = load i32* @x ; <i32> [#uses=1]
%1 = icmp ne i32 %0, 0 ; <i1> [#uses=1]
br i1 %1, label %land_rhs, label %land_cont
land_rhs: ; preds = %entry
%2 = load i32* @y ; <i32> [#uses=1]
%3 = icmp ne i32 %2, 0 ; <i1> [#uses=1]
br label %land_cont
land_cont: ; preds = %land_rhs, %entry
%4 = phi i1 [ false, %entry ], [ %3, %land_rhs ] ; <i1> [#uses=1]
br i1 %4, label %ifthen, label %ifelse
ifthen: ; preds = %land_cont
%call = call i32 (...)* @foo() ; <i32> [#uses=0]
br label %ifend
ifelse: ; preds = %land_cont
%call1 = call i32 (...)* @bar() ; <i32> [#uses=0]
br label %ifend
ifend: ; preds = %ifelse, %ifthen
Now we turn it into the much more svelte code:
%0 = load i32* @x ; <i32> [#uses=1]
%1 = icmp ne i32 %0, 0 ; <i1> [#uses=1]
br i1 %1, label %land_lhs_true, label %ifelse
land_lhs_true: ; preds = %entry
%2 = load i32* @y ; <i32> [#uses=1]
%3 = icmp ne i32 %2, 0 ; <i1> [#uses=1]
br i1 %3, label %ifthen, label %ifelse
ifthen: ; preds = %land_lhs_true
%call = call i32 (...)* @foo() ; <i32> [#uses=0]
br label %ifend
ifelse: ; preds = %land_lhs_true, %entry
%call1 = call i32 (...)* @bar() ; <i32> [#uses=0]
br label %ifend
ifend: ; preds = %ifelse, %ifthen
Note the lack of a phi node.
This shrinks the -O0 .ll file for 176.gcc/expr.c from 43176 to 40267 lines.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@59111 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen/CGStmt.cpp')
-rw-r--r-- | lib/CodeGen/CGStmt.cpp | 113 |
1 files changed, 99 insertions, 14 deletions
diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp index 7f9ca7af7f..551a4c040b 100644 --- a/lib/CodeGen/CGStmt.cpp +++ b/lib/CodeGen/CGStmt.cpp @@ -14,6 +14,7 @@ #include "CGDebugInfo.h" #include "CodeGenModule.h" #include "CodeGenFunction.h" +#include "clang/AST/APValue.h" #include "clang/AST/StmtVisitor.h" #include "clang/Basic/TargetInfo.h" #include "llvm/InlineAsm.h" @@ -223,37 +224,121 @@ void CodeGenFunction::EmitIndirectGotoStmt(const IndirectGotoStmt &S) { Builder.ClearInsertionPoint(); } + +/// ConstantFoldsToSimpleInteger - If the sepcified expression does not fold to +/// a constant, or if it does but contains a label, return 0. If it constant +/// folds to 'true' and does not contain a label, return 1, if it constant folds +/// to 'false' and does not contain a label, return -1. +static int ConstantFoldsToSimpleInteger(const Expr *Cond, ASTContext &Ctx) { + APValue V; + if (!Cond->tryEvaluate(V, Ctx)) + return 0; // Not foldable. + + if (CodeGenFunction::ContainsLabel(Cond)) + return 0; // Contains a label. + + return V.getInt().getBoolValue() ? 1 : -1; +} + + +/// EmitBranchOnBoolExpr - Emit a branch on a boolean condition (e.g. for an if +/// statement) to the specified blocks. Based on the condition, this might try +/// to simplify the codegen of the conditional based on the branch. +/// +void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond, + llvm::BasicBlock *TrueBlock, + llvm::BasicBlock *FalseBlock) { + if (const ParenExpr *PE = dyn_cast<ParenExpr>(Cond)) + return EmitBranchOnBoolExpr(PE->getSubExpr(), TrueBlock, FalseBlock); + + if (const BinaryOperator *CondBOp = dyn_cast<BinaryOperator>(Cond)) { + // Handle X && Y in a condition. + if (CondBOp->getOpcode() == BinaryOperator::LAnd) { + // If we have "1 && X", simplify the code. "0 && X" would have constant + // folded if the case was simple enough. + if (ConstantFoldsToSimpleInteger(CondBOp->getLHS(), getContext()) == 1) { + // br(1 && X) -> br(X). + return EmitBranchOnBoolExpr(CondBOp->getRHS(), TrueBlock, FalseBlock); + } + + // If we have "X && 1", simplify the code to use an uncond branch. + // "X && 0" would have been constant folded to 0. + if (ConstantFoldsToSimpleInteger(CondBOp->getRHS(), getContext()) == 1) { + // br(X && 1) -> br(X). + return EmitBranchOnBoolExpr(CondBOp->getLHS(), TrueBlock, FalseBlock); + } + + // Emit the LHS as a conditional. If the LHS conditional is false, we + // want to jump to the FalseBlock. + llvm::BasicBlock *LHSTrue = createBasicBlock("land_lhs_true"); + EmitBranchOnBoolExpr(CondBOp->getLHS(), LHSTrue, FalseBlock); + EmitBlock(LHSTrue); + + EmitBranchOnBoolExpr(CondBOp->getRHS(), TrueBlock, FalseBlock); + return; + } else if (CondBOp->getOpcode() == BinaryOperator::LOr) { + // If we have "0 || X", simplify the code. "1 || X" would have constant + // folded if the case was simple enough. + if (ConstantFoldsToSimpleInteger(CondBOp->getLHS(), getContext()) == -1) { + // br(0 || X) -> br(X). + return EmitBranchOnBoolExpr(CondBOp->getRHS(), TrueBlock, FalseBlock); + } + + // If we have "X || 0", simplify the code to use an uncond branch. + // "X || 1" would have been constant folded to 1. + if (ConstantFoldsToSimpleInteger(CondBOp->getRHS(), getContext()) == -1) { + // br(X || 0) -> br(X). + return EmitBranchOnBoolExpr(CondBOp->getLHS(), TrueBlock, FalseBlock); + } + + // Emit the LHS as a conditional. If the LHS conditional is true, we + // want to jump to the TrueBlock. + llvm::BasicBlock *LHSFalse = createBasicBlock("lor_lhs_false"); + EmitBranchOnBoolExpr(CondBOp->getLHS(), TrueBlock, LHSFalse); + EmitBlock(LHSFalse); + + EmitBranchOnBoolExpr(CondBOp->getRHS(), TrueBlock, FalseBlock); + return; + } + + } + + // Emit the code with the fully general case. + llvm::Value *CondV = EvaluateExprAsBool(Cond); + Builder.CreateCondBr(CondV, TrueBlock, FalseBlock); +} + + void CodeGenFunction::EmitIfStmt(const IfStmt &S) { // C99 6.8.4.1: The first substatement is executed if the expression compares // unequal to 0. The condition must be a scalar type. - llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond()); - // If we constant folded the condition to true or false, try to avoid emitting - // the dead arm at all. - if (llvm::ConstantInt *CondCst = dyn_cast<llvm::ConstantInt>(BoolCondVal)) { + // If the condition constant folds and can be elided, try to avoid emitting + // the condition and the dead arm of the if/else. + if (int Cond = ConstantFoldsToSimpleInteger(S.getCond(), getContext())) { // Figure out which block (then or else) is executed. const Stmt *Executed = S.getThen(), *Skipped = S.getElse(); - if (CondCst->isZero()) + if (Cond == -1) // Condition false? std::swap(Executed, Skipped); - + // If the skipped block has no labels in it, just emit the executed block. // This avoids emitting dead code and simplifies the CFG substantially. - if (Skipped == 0 || !ContainsLabel(Skipped)) { + if (!ContainsLabel(Skipped)) { if (Executed) EmitStmt(Executed); return; } } - - llvm::BasicBlock *ContBlock = createBasicBlock("ifend"); + + // Otherwise, the condition did not fold, or we couldn't elide it. Just emit + // the conditional branch. llvm::BasicBlock *ThenBlock = createBasicBlock("ifthen"); - llvm::BasicBlock *ElseBlock = ContBlock; + llvm::BasicBlock *ElseBlock = createBasicBlock("ifelse"); + EmitBranchOnBoolExpr(S.getCond(), ThenBlock, ElseBlock); + llvm::BasicBlock *ContBlock = ElseBlock; if (S.getElse()) - ElseBlock = createBasicBlock("ifelse"); - - // Insert the conditional branch. - Builder.CreateCondBr(BoolCondVal, ThenBlock, ElseBlock); + ContBlock = createBasicBlock("ifend"); // Emit the 'then' code. EmitBlock(ThenBlock); |