Chromium Code Reviews| Index: lib/Transforms/NaCl/ExpandIndirectBr.cpp |
| diff --git a/lib/Transforms/NaCl/ExpandIndirectBr.cpp b/lib/Transforms/NaCl/ExpandIndirectBr.cpp |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..63e44d5567c69b77e25b5f470da5a70e4a6aa44a |
| --- /dev/null |
| +++ b/lib/Transforms/NaCl/ExpandIndirectBr.cpp |
| @@ -0,0 +1,152 @@ |
| +//===- ExpandIndirectBr.cpp - Expand out indirectbr and blockaddress-------===// |
| +// |
| +// The LLVM Compiler Infrastructure |
| +// |
| +// This file is distributed under the University of Illinois Open Source |
| +// License. See LICENSE.TXT for details. |
| +// |
| +//===----------------------------------------------------------------------===// |
| +// |
| +// This pass expands out indirectbr instructions and blockaddress |
| +// ConstantExprs, which are not currently supported in PNaCl's stable |
| +// ABI. indirectbr is used to implement computed gotos (a GNU |
| +// extension to C). This pass replaces indirectbr instructions with |
| +// switch instructions. |
| +// |
| +// The resulting use of switches might not be as fast as the original |
| +// indirectbrs. If you are compiling a program that has a |
| +// compile-time option for using computed gotos, it's possible that |
| +// the program will run faster with the option turned off than with |
| +// using computed gotos + ExpandIndirectBr (for example, if the |
| +// program does extra work to take advantage of computed gotos). |
| +// |
| +//===----------------------------------------------------------------------===// |
| + |
| +#include "llvm/ADT/DenseMap.h" |
| +#include "llvm/ADT/DenseSet.h" |
| +#include "llvm/IR/Constants.h" |
| +#include "llvm/IR/Instructions.h" |
| +#include "llvm/IR/Module.h" |
| +#include "llvm/Pass.h" |
| +#include "llvm/Transforms/NaCl.h" |
| + |
| +using namespace llvm; |
| + |
| +namespace { |
| + // This is a ModulePass so that it can expand out blockaddress |
| + // ConstantExprs inside global variable initializers. |
| + class ExpandIndirectBr : public ModulePass { |
| + public: |
| + static char ID; // Pass identification, replacement for typeid |
| + ExpandIndirectBr() : ModulePass(ID) { |
| + initializeExpandIndirectBrPass(*PassRegistry::getPassRegistry()); |
| + } |
| + |
| + virtual bool runOnModule(Module &M); |
| + }; |
| +} |
| + |
| +char ExpandIndirectBr::ID = 0; |
| +INITIALIZE_PASS(ExpandIndirectBr, "expand-indirectbr", |
| + "Expand out indirectbr and blockaddress (computed gotos)", |
| + false, false) |
| + |
| +static bool convertFunction(Function *Func) { |
| + bool Changed = false; |
| + IntegerType *I32 = Type::getInt32Ty(Func->getContext()); |
| + |
| + // Skip zero in case programs treat a null pointer as special. |
| + uint32_t NextNum = 1; |
| + DenseMap<BasicBlock *, ConstantInt *> LabelNums; |
| + BasicBlock *DefaultBB = NULL; |
| + |
| + // Replace each indirectbr with a switch. |
| + // |
| + // If there are multiple indirectbr instructions in the function, |
| + // this could be expensive. While an indirectbr is usually |
| + // converted to O(1) machine instructions, the switch we generate |
| + // here will be O(n) in the number of target labels. |
| + // |
| + // However, Clang usually generates just a single indirectbr per |
| + // function anyway when compiling C computed gotos. |
| + // |
| + // We could try to generate one switch to handle all the indirectbr |
| + // instructions in the function, but that would be complicated to |
| + // implement given that variables that are live at one indirectbr |
| + // might not be live at others. |
| + for (llvm::Function::iterator BB = Func->begin(), E = Func->end(); |
| + BB != E; ++BB) { |
| + if (IndirectBrInst *Br = dyn_cast<IndirectBrInst>(BB->getTerminator())) { |
| + Changed = true; |
| + |
| + if (!DefaultBB) { |
| + DefaultBB = BasicBlock::Create(Func->getContext(), |
| + "indirectbr_default", Func); |
| + new UnreachableInst(Func->getContext(), DefaultBB); |
| + } |
| + |
| + // An indirectbr can list the same target block multiple times. |
| + // Keep track of the basic blocks we've handled to avoid adding |
| + // the same case multiple times. |
| + DenseSet<BasicBlock *> BlocksSeen; |
| + |
| + Value *Cast = new PtrToIntInst(Br->getAddress(), I32, |
| + "indirectbr_cast", Br); |
| + unsigned Count = Br->getNumSuccessors(); |
| + SwitchInst *Switch = SwitchInst::Create(Cast, DefaultBB, Count, Br); |
| + for (unsigned I = 0; I < Count; ++I) { |
| + BasicBlock *Dest = Br->getSuccessor(I); |
| + if (!BlocksSeen.insert(Dest).second) { |
| + // Remove duplicated entries from phi nodes. |
| + for (BasicBlock::iterator Inst = Dest->begin(); ; ++Inst) { |
| + PHINode *Phi = dyn_cast<PHINode>(Inst); |
| + if (!Phi) |
| + break; |
| + Phi->removeIncomingValue(Br->getParent()); |
| + } |
| + continue; |
| + } |
| + ConstantInt *Val; |
| + if (LabelNums.count(Dest) == 0) { |
| + Val = ConstantInt::get(I32, NextNum++); |
| + LabelNums[Dest] = Val; |
| + |
| + BlockAddress *BA = BlockAddress::get(Func, Dest); |
| + Value *ValAsPtr = ConstantExpr::getIntToPtr(Val, BA->getType()); |
| + BA->replaceAllUsesWith(ValAsPtr); |
| + BA->destroyConstant(); |
| + } else { |
| + Val = LabelNums[Dest]; |
| + } |
| + Switch->addCase(Val, Br->getSuccessor(I)); |
| + } |
| + Br->eraseFromParent(); |
| + } |
| + } |
| + |
| + // If there are any blockaddresses that are never used by an |
| + // 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
|
| + for (Value::use_iterator UI = Func->use_begin(), E = Func->use_end(); |
| + UI != E; ++UI) { |
| + if (BlockAddress *BA = dyn_cast<BlockAddress>(*UI)) { |
| + Changed = true; |
| + Value *DummyVal = ConstantExpr::getIntToPtr(ConstantInt::get(I32, ~0L), |
| + BA->getType()); |
| + BA->replaceAllUsesWith(DummyVal); |
| + BA->destroyConstant(); |
| + } |
| + } |
| + return Changed; |
| +} |
| + |
| +bool ExpandIndirectBr::runOnModule(Module &M) { |
| + bool Changed = false; |
| + for (Module::iterator Func = M.begin(), E = M.end(); Func != E; ++Func) { |
| + Changed |= convertFunction(Func); |
| + } |
| + return Changed; |
| +} |
| + |
| +ModulePass *llvm::createExpandIndirectBrPass() { |
| + return new ExpandIndirectBr(); |
| +} |