about summary refs log tree commit diff homepage
path: root/lib/Module/LowerSwitch.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Module/LowerSwitch.cpp')
-rw-r--r--lib/Module/LowerSwitch.cpp134
1 files changed, 134 insertions, 0 deletions
diff --git a/lib/Module/LowerSwitch.cpp b/lib/Module/LowerSwitch.cpp
new file mode 100644
index 00000000..a1b887f3
--- /dev/null
+++ b/lib/Module/LowerSwitch.cpp
@@ -0,0 +1,134 @@
+//===-- LowerSwitch.cpp - Eliminate Switch instructions -------------------===//
+//
+//                     The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Derived from LowerSwitch.cpp in LLVM, heavily modified by piotrek
+// to get rid of the binary search transform, as it was creating
+// multiple paths through the program (i.e., extra paths that didn't
+// exist in the original program).
+//
+//===----------------------------------------------------------------------===//
+
+#include "Passes.h"
+#include <algorithm>
+
+using namespace llvm;
+
+namespace klee {
+
+char LowerSwitchPass::ID = 0;
+
+// The comparison function for sorting the switch case values in the vector.
+struct SwitchCaseCmp {
+  bool operator () (const LowerSwitchPass::SwitchCase& C1,
+                    const LowerSwitchPass::SwitchCase& C2) {
+    
+    const ConstantInt* CI1 = cast<const ConstantInt>(C1.value);
+    const ConstantInt* CI2 = cast<const ConstantInt>(C2.value);
+    return CI1->getValue().slt(CI2->getValue());
+  }
+};
+
+bool LowerSwitchPass::runOnFunction(Function &F) {
+  bool changed = false;
+
+  for (Function::iterator I = F.begin(), E = F.end(); I != E; ) {
+    BasicBlock *cur = I++; // Advance over block so we don't traverse new blocks
+
+    if (SwitchInst *SI = dyn_cast<SwitchInst>(cur->getTerminator())) {
+      changed = true;
+      processSwitchInst(SI);
+    }
+  }
+
+  return changed;
+}
+
+// switchConvert - Convert the switch statement into a linear scan
+// through all the case values
+void LowerSwitchPass::switchConvert(CaseItr begin, CaseItr end,
+                                    Value* value, BasicBlock* origBlock,
+                                    BasicBlock* defaultBlock)
+{
+  BasicBlock *curHead = defaultBlock;
+  Function *F = origBlock->getParent();
+  
+  // iterate through all the cases, creating a new BasicBlock for each
+  for (CaseItr it = begin; it < end; ++it) {
+    BasicBlock *newBlock = BasicBlock::Create("NodeBlock");
+    Function::iterator FI = origBlock;
+    F->getBasicBlockList().insert(++FI, newBlock);
+    
+    ICmpInst *cmpInst = new ICmpInst(ICmpInst::ICMP_EQ,
+                                     value,
+                                     it->value,
+                                     "Case Comparison");
+    
+    newBlock->getInstList().push_back(cmpInst);
+    BranchInst::Create(it->block, curHead, cmpInst, newBlock);
+
+    // If there were any PHI nodes in this successor, rewrite one entry
+    // from origBlock to come from newBlock.
+    for (BasicBlock::iterator bi = it->block->begin(); isa<PHINode>(bi); ++bi) {
+      PHINode* PN = cast<PHINode>(bi);
+
+      int blockIndex = PN->getBasicBlockIndex(origBlock);
+      assert(blockIndex != -1 && "Switch didn't go to this successor??");
+      PN->setIncomingBlock((unsigned)blockIndex, newBlock);
+    }
+    
+    curHead = newBlock;
+  }
+
+  // Branch to our shiny new if-then stuff...
+  BranchInst::Create(curHead, origBlock);
+}
+
+// processSwitchInst - Replace the specified switch instruction with a sequence
+// of chained if-then instructions.
+//
+void LowerSwitchPass::processSwitchInst(SwitchInst *SI) {
+  BasicBlock *origBlock = SI->getParent();
+  BasicBlock *defaultBlock = SI->getDefaultDest();
+  Function *F = origBlock->getParent();
+  Value *switchValue = SI->getOperand(0);
+
+  // Create a new, empty default block so that the new hierarchy of
+  // if-then statements go to this and the PHI nodes are happy.
+  BasicBlock* newDefault = BasicBlock::Create("newDefault");
+
+  F->getBasicBlockList().insert(defaultBlock, newDefault);
+  BranchInst::Create(defaultBlock, newDefault);
+
+  // If there is an entry in any PHI nodes for the default edge, make sure
+  // to update them as well.
+  for (BasicBlock::iterator I = defaultBlock->begin(); isa<PHINode>(I); ++I) {
+    PHINode *PN = cast<PHINode>(I);
+    int BlockIdx = PN->getBasicBlockIndex(origBlock);
+    assert(BlockIdx != -1 && "Switch didn't go to this successor??");
+    PN->setIncomingBlock((unsigned)BlockIdx, newDefault);
+  }
+  
+  CaseVector cases;
+  for (unsigned i = 1; i < SI->getNumSuccessors(); ++i)
+    cases.push_back(SwitchCase(SI->getSuccessorValue(i),
+                               SI->getSuccessor(i)));
+  
+  // reverse cases, as switchConvert constructs a chain of
+  //   basic blocks by appending to the front. if we reverse,
+  //   the if comparisons will happen in the same order
+  //   as the cases appear in the switch
+  std::reverse(cases.begin(), cases.end());
+  
+  switchConvert(cases.begin(), cases.end(), switchValue, origBlock, newDefault);
+
+  // We are now done with the switch instruction, so delete it
+  origBlock->getInstList().erase(SI);
+}
+
+}