[llvm-commits] CVS: llvm/lib/Transforms/Utils/SimplifyCFG.cpp

Chris Lattner lattner at cs.uiuc.edu
Thu Feb 26 01:14:01 PST 2004


Changes in directory llvm/lib/Transforms/Utils:

SimplifyCFG.cpp updated: 1.27 -> 1.28

---
Log message:

turn things like:
   if (X == 0 || X == 2)

...where the comparisons and branches are in different blocks... into a switch 
instruction.  This comes up a lot in various programs, and works well with
the switch/switch merging code I checked earlier.  For example, this testcase:

int switchtest(int C) {
  return C == 0 ? f(123) :
         C == 1 ? f(3123) :
         C == 4 ? f(312) :
         C == 5 ? f(1234): f(444);
}

is converted into this:
        switch int %C, label %cond_false.3 [
                 int 0, label %cond_true.0
                 int 1, label %cond_true.1
                 int 4, label %cond_true.2
                 int 5, label %cond_true.3
        ]

instead of a whole bunch of conditional branches.

Admittedly the code is ugly, and incomplete.  To be complete, we need to add
br -> switch merging and switch -> br merging.  For example, this testcase:

struct foo { int Q, R, Z; };
#define A (X->Q+X->R * 123)
int test(struct foo *X) {
  return A  == 123 ? X1() :
        A == 12321 ? X2():
        (A == 111 || A == 222) ? X3() :
        A == 875 ? X4() : X5();
}

Gets compiled to this:
        switch int %tmp.7, label %cond_false.2 [
                 int 123, label %cond_true.0
                 int 12321, label %cond_true.1
                 int 111, label %cond_true.2
                 int 222, label %cond_true.2
        ]
...
cond_false.2:           ; preds = %entry
        %tmp.52 = seteq int %tmp.7, 875         ; <bool> [#uses=1]
        br bool %tmp.52, label %cond_true.3, label %cond_false.3

where the branch could be folded into the switch.

This kind of thing occurs *ALL OF THE TIME*, especially in programs like
176.gcc, which is a horrible mess of code.  It contains stuff like *shudder*:

#define SWITCH_TAKES_ARG(CHAR) \
  (   (CHAR) == 'D' \
   || (CHAR) == 'U' \
   || (CHAR) == 'o' \
   || (CHAR) == 'e' \
   || (CHAR) == 'u' \
   || (CHAR) == 'I' \
   || (CHAR) == 'm' \
   || (CHAR) == 'L' \
   || (CHAR) == 'A' \
   || (CHAR) == 'h' \
   || (CHAR) == 'z')

and 

#define CONST_OK_FOR_LETTER_P(VALUE, C)                 \
  ((C) == 'I' ? SMALL_INTVAL (VALUE)                    \
   : (C) == 'J' ? SMALL_INTVAL (-(VALUE))               \
   : (C) == 'K' ? (unsigned)(VALUE) < 32                \
   : (C) == 'L' ? ((VALUE) & 0xffff) == 0               \
   : (C) == 'M' ? integer_ok_for_set (VALUE)            \
   : (C) == 'N' ? (VALUE) < 0                           \
   : (C) == 'O' ? (VALUE) == 0                          \
   : (C) == 'P' ? (VALUE) >= 0                          \
   : 0)

and

#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN)                     \
{                                                               \
  if (GET_CODE (X) == PLUS && CONSTANT_ADDRESS_P (XEXP (X, 1))) \
    (X) = gen_rtx (PLUS, SImode, XEXP (X, 0),                   \
                   copy_to_mode_reg (SImode, XEXP (X, 1)));     \
  if (GET_CODE (X) == PLUS && CONSTANT_ADDRESS_P (XEXP (X, 0))) \
    (X) = gen_rtx (PLUS, SImode, XEXP (X, 1),                   \
                   copy_to_mode_reg (SImode, XEXP (X, 0)));     \
  if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 0)) == MULT)   \
    (X) = gen_rtx (PLUS, SImode, XEXP (X, 1),                   \
                   force_operand (XEXP (X, 0), 0));             \
  if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == MULT)   \
    (X) = gen_rtx (PLUS, SImode, XEXP (X, 0),                   \
                   force_operand (XEXP (X, 1), 0));             \
  if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 0)) == PLUS)   \
    (X) = gen_rtx (PLUS, Pmode, force_operand (XEXP (X, 0), NULL_RTX),\
                   XEXP (X, 1));                                \
  if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == PLUS)   \
    (X) = gen_rtx (PLUS, Pmode, XEXP (X, 0),                    \
                   force_operand (XEXP (X, 1), NULL_RTX));      \
  if (GET_CODE (X) == SYMBOL_REF || GET_CODE (X) == CONST       \
           || GET_CODE (X) == LABEL_REF)                        \
    (X) = legitimize_address (flag_pic, X, 0, 0);               \
  if (memory_address_p (MODE, X))                               \
    goto WIN; }

and others.  These macros get used multiple times of course.  These are such
lovely candidates for macros, aren't they?  :)

This code also nicely handles LLVM constructs that look like this:

  if (isa<CastInst>(I))
   ...
  else if (isa<BranchInst>(I))
   ...
  else if (isa<SetCondInst>(I))
   ...
  else if (isa<UnwindInst>(I))
   ...
  else if (isa<VAArgInst>(I))
   ...

where the isa can obviously be a dyn_cast as well.  Switch instructions are a 
good thing.



---
Diffs of the changes:  (+74 -0)

Index: llvm/lib/Transforms/Utils/SimplifyCFG.cpp
diff -u llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.27 llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.28
--- llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.27	Tue Feb 24 10:09:21 2004
+++ llvm/lib/Transforms/Utils/SimplifyCFG.cpp	Thu Feb 26 01:13:46 2004
@@ -690,6 +690,80 @@
     return true;
   }
 
+  // If there is a single predecessor for this block, and if this block is a
+  // simple value comparison block (ie, contains X == C), see if we can fold
+  // this comparison into the comparison in our predecessor block, making the
+  // predecessor block terminator into a switch (or adding cases to a
+  // preexisting switch).
+  if (OnlyPred) {
+    if (SetCondInst *SCI = dyn_cast<SetCondInst>(BB->begin()))
+      if (SCI->getOpcode() == Instruction::SetEQ && SCI->hasOneUse() &&
+          isa<BranchInst>(SCI->use_back()) &&
+          SCI->getNext() == cast<BranchInst>(SCI->use_back())) {
+        // Okay, we know we have a block containing (only) a seteq and a
+        // conditional branch instruction.  If an integer value is being
+        // compared, if the comparison value is a constant, then check the
+        // predecessor.
+        BranchInst *BBBr = cast<BranchInst>(BB->getTerminator());
+        Value *CompVal = SCI->getOperand(0);
+        if (ConstantInt *CVal = dyn_cast<ConstantInt>(SCI->getOperand(1))) {
+          // We can do the merge if the predecessor contains either a
+          // conditional branch or a switch instruction which is operating on
+          // the CompVal.
+          if (BranchInst *BI = dyn_cast<BranchInst>(OnlyPred->getTerminator())){
+            // If it is a branch, then it must be a conditional branch,
+            // otherwise we would have merged it in before.  We can only handle
+            // this if the block we are looking at is the 'false' branch.
+            assert(BI->isConditional() &&
+                   "Should have previously merged blocks!");
+            if (SetCondInst *PredSCC= dyn_cast<SetCondInst>(BI->getCondition()))
+              if (PredSCC->getOperand(0) == CompVal &&
+                  PredSCC->getOpcode() == Instruction::SetEQ &&
+                  isa<ConstantInt>(PredSCC->getOperand(1)) &&
+                  BB == BI->getSuccessor(1) &&
+                  SafeToMergeTerminators(BI, BBBr)) {
+                // If the constants being compared are the same, then the
+                // comparison in this block could never come true.
+                if (SCI->getOperand(1) == PredSCC->getOperand(1)) {
+                  // Tell the block to skip over us, making us dead.
+                  BI->setSuccessor(1, BBBr->getSuccessor(1));
+                  AddPredecessorToBlock(BBBr->getSuccessor(1), OnlyPred, BB);
+                  return SimplifyCFG(BB);
+                }
+
+                // Otherwise, create the switch instruction!
+                SwitchInst *SI = new SwitchInst(CompVal, BBBr->getSuccessor(1),
+                                                BI);
+                // Add the edge from our predecessor, and remove the
+                // predecessors (now obsolete branch instruction).  This makes
+                // the current block dead.
+                SI->addCase(cast<Constant>(PredSCC->getOperand(1)),
+                            BI->getSuccessor(0));
+                OnlyPred->getInstList().erase(BI);
+                if (PredSCC->use_empty())
+                  PredSCC->getParent()->getInstList().erase(PredSCC);
+
+                // Add our case...
+                SI->addCase(cast<Constant>(SCI->getOperand(1)),
+                            BBBr->getSuccessor(0));
+
+                AddPredecessorToBlock(BBBr->getSuccessor(0), OnlyPred, BB);
+                AddPredecessorToBlock(BBBr->getSuccessor(1), OnlyPred, BB);
+
+                //std::cerr << "Formed Switch: " << SI;
+
+                // Made a big change!  Now this block is dead, so remove it.
+                return SimplifyCFG(BB);
+              }
+
+          } else if (SwitchInst *SI =
+                     dyn_cast<SwitchInst>(OnlyPred->getTerminator())) {
+
+          }
+        }
+      }
+  }
+
   for (pred_iterator PI = pred_begin(BB), E = pred_end(BB); PI != E; ++PI)
     if (BranchInst *BI = dyn_cast<BranchInst>((*PI)->getTerminator()))
       // Change br (X == 0 | X == 1), T, F into a switch instruction.





More information about the llvm-commits mailing list