[cfe-commits] r59111 - in /cfe/trunk/lib/CodeGen: CGStmt.cpp CodeGenFunction.h

Chris Lattner sabre at nondot.org
Tue Nov 11 23:46:33 PST 2008


Author: lattner
Date: Wed Nov 12 01:46:33 2008
New Revision: 59111

URL: http://llvm.org/viewvc/llvm-project?rev=59111&view=rev
Log:
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.


Modified:
    cfe/trunk/lib/CodeGen/CGStmt.cpp
    cfe/trunk/lib/CodeGen/CodeGenFunction.h

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

==============================================================================
--- cfe/trunk/lib/CodeGen/CGStmt.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGStmt.cpp Wed Nov 12 01:46:33 2008
@@ -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 @@
   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);

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

==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Wed Nov 12 01:46:33 2008
@@ -564,6 +564,8 @@
   static bool ContainsLabel(const Stmt *S, bool IgnoreCaseStmts = false);
   
 private:
+  void EmitBranchOnBoolExpr(const Expr *Cond, llvm::BasicBlock *TrueBlock,
+                            llvm::BasicBlock *FalseBlock);
   
   /// EmitIndirectSwitches - Emit code for all of the switch
   /// instructions in IndirectSwitches.





More information about the cfe-commits mailing list