From: Chris Lattner Date: Tue, 11 Nov 2008 07:41:27 +0000 (+0000) Subject: short circuit && and || when possible. This substantially reduces X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0946ccd1e58c1f1da31ddbca67c5b6301ac8b255;p=clang short circuit && and || when possible. This substantially reduces the size of the -O0 output on some cases. For example, on expr.c from 176.gcc, it shrinks the .ll file from 43164 to 42835 lines, and removed references to two external symbols. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@59034 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index 7d3157b03d..4a17938357 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -1028,6 +1028,20 @@ Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) { Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) { Value *LHSCond = CGF.EvaluateExprAsBool(E->getLHS()); + if (llvm::ConstantInt *LHSCst = dyn_cast(LHSCond)) { + // If we have 0 && RHS, see if we can elide RHS, if so, just return LHSCond. + if (LHSCst->getZExtValue() == 0) { + if (!CGF.ContainsLabel(E->getRHS())) + // Elide RHS, return 0 + return llvm::Constant::getNullValue(CGF.LLVMIntTy); + } else { + // If we have 1 && X, just emit X without inserting the control flow. + Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS()); + // ZExt result to int. + return Builder.CreateZExt(RHSCond, CGF.LLVMIntTy, "land.ext"); + } + } + llvm::BasicBlock *ContBlock = llvm::BasicBlock::Create("land_cont"); llvm::BasicBlock *RHSBlock = llvm::BasicBlock::Create("land_rhs"); @@ -1055,6 +1069,20 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) { Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) { Value *LHSCond = CGF.EvaluateExprAsBool(E->getLHS()); + if (llvm::ConstantInt *LHSCst = dyn_cast(LHSCond)) { + // If we have 1 || RHS, see if we can elide RHS, if so, just return LHSCond. + if (LHSCst->getZExtValue() != 0) { + if (!CGF.ContainsLabel(E->getRHS())) + // Elide RHS, return 1 + return llvm::ConstantInt::get(CGF.LLVMIntTy, 1); + } else { + // If we have 0 || X, just emit X without inserting the control flow. + Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS()); + // ZExt result to int. + return Builder.CreateZExt(RHSCond, CGF.LLVMIntTy, "lor.ext"); + } + } + llvm::BasicBlock *ContBlock = CGF.createBasicBlock("lor_cont"); llvm::BasicBlock *RHSBlock = CGF.createBasicBlock("lor_rhs"); diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp index 1d9b30eca8..b042261ec3 100644 --- a/lib/CodeGen/CGStmt.cpp +++ b/lib/CodeGen/CGStmt.cpp @@ -217,34 +217,6 @@ void CodeGenFunction::EmitIndirectGotoStmt(const IndirectGotoStmt &S) { EmitDummyBlock(); } -/// ContainsLabel - Return true if the statement contains a label in it. If -/// this statement is not executed normally, it not containing a label means -/// that we can just remove the code. -static bool ContainsLabel(const Stmt *S, bool IgnoreCaseStmts = false) { - // If this is a label, we have to emit the code, consider something like: - // if (0) { ... foo: bar(); } goto foo; - if (isa(S)) - return true; - - // If this is a case/default statement, and we haven't seen a switch, we have - // to emit the code. - if (isa(S) && !IgnoreCaseStmts) - return true; - - // If this is a switch statement, we want to ignore cases below it. - if (isa(S)) - IgnoreCaseStmts = true; - - // Scan subexpressions for verboten labels. - for (Stmt::const_child_iterator I = S->child_begin(), E = S->child_end(); - I != E; ++I) - if (ContainsLabel(*I, IgnoreCaseStmts)) - return true; - - return false; -} - - 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. diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index 427f6457bb..1a26610d75 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -163,6 +163,36 @@ bool CodeGenFunction::isDummyBlock(const llvm::BasicBlock *BB) { return false; } +/// ContainsLabel - Return true if the statement contains a label in it. If +/// this statement is not executed normally, it not containing a label means +/// that we can just remove the code. +bool CodeGenFunction::ContainsLabel(const Stmt *S, bool IgnoreCaseStmts) { + // Null statement, not a label! + if (S == 0) return false; + + // If this is a label, we have to emit the code, consider something like: + // if (0) { ... foo: bar(); } goto foo; + if (isa(S)) + return true; + + // If this is a case/default statement, and we haven't seen a switch, we have + // to emit the code. + if (isa(S) && !IgnoreCaseStmts) + return true; + + // If this is a switch statement, we want to ignore cases below it. + if (isa(S)) + IgnoreCaseStmts = true; + + // Scan subexpressions for verboten labels. + for (Stmt::const_child_iterator I = S->child_begin(), E = S->child_end(); + I != E; ++I) + if (ContainsLabel(*I, IgnoreCaseStmts)) + return true; + + return false; +} + /// getCGRecordLayout - Return record layout info. const CGRecordLayout *CodeGenFunction::getCGRecordLayout(CodeGenTypes &CGT, QualType Ty) { diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index a454cece40..04d64e4ee1 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -513,7 +513,13 @@ public: // Internal Helpers //===--------------------------------------------------------------------===// + /// ContainsLabel - Return true if the statement contains a label in it. If + /// this statement is not executed normally, it not containing a label means + /// that we can just remove the code. + static bool ContainsLabel(const Stmt *S, bool IgnoreCaseStmts = false); + private: + /// EmitIndirectSwitches - Emit code for all of the switch /// instructions in IndirectSwitches. void EmitIndirectSwitches();