Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(42)

Side by Side Diff: lib/Transforms/NaCl/ExpandIndirectBr.cpp

Issue 120773002: PNaCl: Implement computed gotos (indirectbr) by expanding out to switches (Closed) Base URL: http://git.chromium.org/native_client/pnacl-llvm.git@master
Patch Set: Cleanup Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « lib/Transforms/NaCl/CMakeLists.txt ('k') | lib/Transforms/NaCl/PNaClABISimplify.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 }
OLDNEW
« no previous file with comments | « lib/Transforms/NaCl/CMakeLists.txt ('k') | lib/Transforms/NaCl/PNaClABISimplify.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698