Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 //===- ExpandIndirectBr.cpp - Expand out indirectbr and blockaddress-------===// | |
| 2 // | |
| 3 // The LLVM Compiler Infrastructure | |
| 4 // | |
| 5 // This file is distributed under the University of Illinois Open Source | |
| 6 // License. See LICENSE.TXT for details. | |
| 7 // | |
| 8 //===----------------------------------------------------------------------===// | |
| 9 // | |
| 10 // This pass expands out indirectbr instructions and blockaddress | |
| 11 // ConstantExprs, which are not currently supported in PNaCl's stable | |
| 12 // ABI. indirectbr is used to implement computed gotos (a GNU | |
| 13 // extension to C). This pass replaces indirectbr instructions with | |
| 14 // switch instructions. | |
| 15 // | |
| 16 // The resulting use of switches might not be as fast as the original | |
| 17 // indirectbrs. If you are compiling a program that has a | |
| 18 // compile-time option for using computed gotos, it's possible that | |
| 19 // the program will run faster with the option turned off than with | |
| 20 // using computed gotos + ExpandIndirectBr (for example, if the | |
| 21 // program does extra work to take advantage of computed gotos). | |
| 22 // | |
| 23 //===----------------------------------------------------------------------===// | |
| 24 | |
| 25 #include "llvm/ADT/DenseMap.h" | |
| 26 #include "llvm/ADT/DenseSet.h" | |
| 27 #include "llvm/IR/Constants.h" | |
| 28 #include "llvm/IR/Instructions.h" | |
| 29 #include "llvm/IR/Module.h" | |
| 30 #include "llvm/Pass.h" | |
| 31 #include "llvm/Transforms/NaCl.h" | |
| 32 | |
| 33 using namespace llvm; | |
| 34 | |
| 35 namespace { | |
| 36 // This is a ModulePass so that it can expand out blockaddress | |
| 37 // ConstantExprs inside global variable initializers. | |
| 38 class ExpandIndirectBr : public ModulePass { | |
| 39 public: | |
| 40 static char ID; // Pass identification, replacement for typeid | |
| 41 ExpandIndirectBr() : ModulePass(ID) { | |
| 42 initializeExpandIndirectBrPass(*PassRegistry::getPassRegistry()); | |
| 43 } | |
| 44 | |
| 45 virtual bool runOnModule(Module &M); | |
| 46 }; | |
| 47 } | |
| 48 | |
| 49 char ExpandIndirectBr::ID = 0; | |
| 50 INITIALIZE_PASS(ExpandIndirectBr, "expand-indirectbr", | |
| 51 "Expand out indirectbr and blockaddress (computed gotos)", | |
| 52 false, false) | |
| 53 | |
| 54 static bool convertFunction(Function *Func) { | |
| 55 bool Changed = false; | |
| 56 IntegerType *I32 = Type::getInt32Ty(Func->getContext()); | |
| 57 | |
| 58 // Skip zero in case programs treat a null pointer as special. | |
| 59 uint32_t NextNum = 1; | |
| 60 DenseMap<BasicBlock *, ConstantInt *> LabelNums; | |
| 61 BasicBlock *DefaultBB = NULL; | |
| 62 | |
| 63 // Replace each indirectbr with a switch. | |
| 64 // | |
| 65 // If there are multiple indirectbr instructions in the function, | |
| 66 // this could be expensive. While an indirectbr is usually | |
| 67 // converted to O(1) machine instructions, the switch we generate | |
| 68 // here will be O(n) in the number of target labels. | |
| 69 // | |
| 70 // However, Clang usually generates just a single indirectbr per | |
| 71 // function anyway when compiling C computed gotos. | |
| 72 // | |
| 73 // We could try to generate one switch to handle all the indirectbr | |
| 74 // instructions in the function, but that would be complicated to | |
| 75 // implement given that variables that are live at one indirectbr | |
| 76 // might not be live at others. | |
| 77 for (llvm::Function::iterator BB = Func->begin(), E = Func->end(); | |
| 78 BB != E; ++BB) { | |
| 79 if (IndirectBrInst *Br = dyn_cast<IndirectBrInst>(BB->getTerminator())) { | |
| 80 Changed = true; | |
| 81 | |
| 82 if (!DefaultBB) { | |
| 83 DefaultBB = BasicBlock::Create(Func->getContext(), | |
| 84 "indirectbr_default", Func); | |
| 85 new UnreachableInst(Func->getContext(), DefaultBB); | |
| 86 } | |
| 87 | |
| 88 // An indirectbr can list the same target block multiple times. | |
| 89 // Keep track of the basic blocks we've handled to avoid adding | |
| 90 // the same case multiple times. | |
| 91 DenseSet<BasicBlock *> BlocksSeen; | |
| 92 | |
| 93 Value *Cast = new PtrToIntInst(Br->getAddress(), I32, | |
| 94 "indirectbr_cast", Br); | |
| 95 unsigned Count = Br->getNumSuccessors(); | |
| 96 SwitchInst *Switch = SwitchInst::Create(Cast, DefaultBB, Count, Br); | |
| 97 for (unsigned I = 0; I < Count; ++I) { | |
| 98 BasicBlock *Dest = Br->getSuccessor(I); | |
| 99 if (!BlocksSeen.insert(Dest).second) { | |
| 100 // Remove duplicated entries from phi nodes. | |
| 101 for (BasicBlock::iterator Inst = Dest->begin(); ; ++Inst) { | |
| 102 PHINode *Phi = dyn_cast<PHINode>(Inst); | |
| 103 if (!Phi) | |
| 104 break; | |
| 105 Phi->removeIncomingValue(Br->getParent()); | |
| 106 } | |
| 107 continue; | |
| 108 } | |
| 109 ConstantInt *Val; | |
| 110 if (LabelNums.count(Dest) == 0) { | |
| 111 Val = ConstantInt::get(I32, NextNum++); | |
| 112 LabelNums[Dest] = Val; | |
| 113 | |
| 114 BlockAddress *BA = BlockAddress::get(Func, Dest); | |
| 115 Value *ValAsPtr = ConstantExpr::getIntToPtr(Val, BA->getType()); | |
| 116 BA->replaceAllUsesWith(ValAsPtr); | |
| 117 BA->destroyConstant(); | |
| 118 } else { | |
| 119 Val = LabelNums[Dest]; | |
| 120 } | |
| 121 Switch->addCase(Val, Br->getSuccessor(I)); | |
| 122 } | |
| 123 Br->eraseFromParent(); | |
| 124 } | |
| 125 } | |
| 126 | |
| 127 // If there are any blockaddresses that are never used by an | |
| 128 // indirectbr, replace them with dummy values. | |
|
Derek Schuff
2014/01/06 22:30:22
Why do this rather than just destroying them?
Mark Seaborn
2014/01/06 22:36:02
Because they might be used, so you can't just dest
Derek Schuff
2014/01/07 00:35:01
Ah, i didn't think there about legitimate uses oth
| |
| 129 for (Value::use_iterator UI = Func->use_begin(), E = Func->use_end(); | |
| 130 UI != E; ++UI) { | |
| 131 if (BlockAddress *BA = dyn_cast<BlockAddress>(*UI)) { | |
| 132 Changed = true; | |
| 133 Value *DummyVal = ConstantExpr::getIntToPtr(ConstantInt::get(I32, ~0L), | |
| 134 BA->getType()); | |
| 135 BA->replaceAllUsesWith(DummyVal); | |
| 136 BA->destroyConstant(); | |
| 137 } | |
| 138 } | |
| 139 return Changed; | |
| 140 } | |
| 141 | |
| 142 bool ExpandIndirectBr::runOnModule(Module &M) { | |
| 143 bool Changed = false; | |
| 144 for (Module::iterator Func = M.begin(), E = M.end(); Func != E; ++Func) { | |
| 145 Changed |= convertFunction(Func); | |
| 146 } | |
| 147 return Changed; | |
| 148 } | |
| 149 | |
| 150 ModulePass *llvm::createExpandIndirectBrPass() { | |
| 151 return new ExpandIndirectBr(); | |
| 152 } | |
| OLD | NEW |