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

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

Issue 939073008: Rebased PNaCl localmods in LLVM to 223109 (Closed)
Patch Set: undo localmod Created 5 years, 9 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/AddPNaClExternalDecls.cpp ('k') | lib/Transforms/NaCl/CMakeLists.txt » ('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 //===- BackendCanonicalize.cpp --------------------------------------------===//
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 // Clean up some toolchain-side PNaCl ABI simplification passes. These passes
11 // allow PNaCl to have a simple and stable ABI, but they sometimes lead to
12 // harder-to-optimize code. This is desirable because LLVM's definition of
13 // "canonical" evolves over time, meaning that PNaCl's simple ABI can stay
14 // simple yet still take full advantage of LLVM's backend by having this pass
15 // massage the code into something that the backend prefers handling.
16 //
17 // It currently:
18 // - Re-generates shufflevector (not part of the PNaCl ABI) from insertelement /
19 // extractelement combinations. This is done by duplicating some of
20 // instcombine's implementation, and ignoring optimizations that should
21 // already have taken place.
22 // - Re-materializes constant loads, especially of vectors. This requires doing
23 // constant folding through bitcasts.
24 //
25 // The pass also performs limited DCE on instructions it knows to be dead,
26 // instead of performing a full global DCE.
27 //
28 //===----------------------------------------------------------------------===//
29
30 #include "llvm/Analysis/ConstantFolding.h"
31 #include "llvm/IR/BasicBlock.h"
32 #include "llvm/IR/DataLayout.h"
33 #include "llvm/IR/IRBuilder.h"
34 #include "llvm/IR/Instruction.h"
35 #include "llvm/IR/Instructions.h"
36 #include "llvm/IR/Operator.h"
37 #include "llvm/IR/InstVisitor.h"
38 #include "llvm/Pass.h"
39 #include "llvm/Target/TargetLibraryInfo.h"
40 #include "llvm/Transforms/NaCl.h"
41 #include "llvm/Transforms/Utils/Local.h"
42
43 using namespace llvm;
44
45 // =============================================================================
46 // TODO(jfb) The following functions are as-is from instcombine. Make them
47 // reusable instead.
48
49 /// CollectSingleShuffleElements - If V is a shuffle of values that ONLY returns
50 /// elements from either LHS or RHS, return the shuffle mask and true.
51 /// Otherwise, return false.
52 static bool CollectSingleShuffleElements(Value *V, Value *LHS, Value *RHS,
53 SmallVectorImpl<Constant*> &Mask) {
54 assert(LHS->getType() == RHS->getType() &&
55 "Invalid CollectSingleShuffleElements");
56 unsigned NumElts = V->getType()->getVectorNumElements();
57
58 if (isa<UndefValue>(V)) {
59 Mask.assign(NumElts, UndefValue::get(Type::getInt32Ty(V->getContext())));
60 return true;
61 }
62
63 if (V == LHS) {
64 for (unsigned i = 0; i != NumElts; ++i)
65 Mask.push_back(ConstantInt::get(Type::getInt32Ty(V->getContext()), i));
66 return true;
67 }
68
69 if (V == RHS) {
70 for (unsigned i = 0; i != NumElts; ++i)
71 Mask.push_back(ConstantInt::get(Type::getInt32Ty(V->getContext()),
72 i+NumElts));
73 return true;
74 }
75
76 if (InsertElementInst *IEI = dyn_cast<InsertElementInst>(V)) {
77 // If this is an insert of an extract from some other vector, include it.
78 Value *VecOp = IEI->getOperand(0);
79 Value *ScalarOp = IEI->getOperand(1);
80 Value *IdxOp = IEI->getOperand(2);
81
82 if (!isa<ConstantInt>(IdxOp))
83 return false;
84 unsigned InsertedIdx = cast<ConstantInt>(IdxOp)->getZExtValue();
85
86 if (isa<UndefValue>(ScalarOp)) { // inserting undef into vector.
87 // We can handle this if the vector we are inserting into is
88 // transitively ok.
89 if (CollectSingleShuffleElements(VecOp, LHS, RHS, Mask)) {
90 // If so, update the mask to reflect the inserted undef.
91 Mask[InsertedIdx] = UndefValue::get(Type::getInt32Ty(V->getContext()));
92 return true;
93 }
94 } else if (ExtractElementInst *EI = dyn_cast<ExtractElementInst>(ScalarOp)){
95 if (isa<ConstantInt>(EI->getOperand(1))) {
96 unsigned ExtractedIdx =
97 cast<ConstantInt>(EI->getOperand(1))->getZExtValue();
98 unsigned NumLHSElts = LHS->getType()->getVectorNumElements();
99
100 // This must be extracting from either LHS or RHS.
101 if (EI->getOperand(0) == LHS || EI->getOperand(0) == RHS) {
102 // We can handle this if the vector we are inserting into is
103 // transitively ok.
104 if (CollectSingleShuffleElements(VecOp, LHS, RHS, Mask)) {
105 // If so, update the mask to reflect the inserted value.
106 if (EI->getOperand(0) == LHS) {
107 Mask[InsertedIdx % NumElts] =
108 ConstantInt::get(Type::getInt32Ty(V->getContext()),
109 ExtractedIdx);
110 } else {
111 assert(EI->getOperand(0) == RHS);
112 Mask[InsertedIdx % NumElts] =
113 ConstantInt::get(Type::getInt32Ty(V->getContext()),
114 ExtractedIdx + NumLHSElts);
115 }
116 return true;
117 }
118 }
119 }
120 }
121 }
122
123 return false;
124 }
125
126 /// We are building a shuffle to create V, which is a sequence of insertelement,
127 /// extractelement pairs. If PermittedRHS is set, then we must either use it or
128 /// not rely on the second vector source. Return a std::pair containing the
129 /// left and right vectors of the proposed shuffle (or 0), and set the Mask
130 /// parameter as required.
131 ///
132 /// Note: we intentionally don't try to fold earlier shuffles since they have
133 /// often been chosen carefully to be efficiently implementable on the target.
134 typedef std::pair<Value *, Value *> ShuffleOps;
135
136 static ShuffleOps CollectShuffleElements(Value *V,
137 SmallVectorImpl<Constant *> &Mask,
138 Value *PermittedRHS) {
139 assert(V->getType()->isVectorTy() && "Invalid shuffle!");
140 unsigned NumElts = cast<VectorType>(V->getType())->getNumElements();
141
142 if (isa<UndefValue>(V)) {
143 Mask.assign(NumElts, UndefValue::get(Type::getInt32Ty(V->getContext())));
144 return std::make_pair(
145 PermittedRHS ? UndefValue::get(PermittedRHS->getType()) : V, nullptr);
146 }
147
148 if (isa<ConstantAggregateZero>(V)) {
149 Mask.assign(NumElts, ConstantInt::get(Type::getInt32Ty(V->getContext()),0));
150 return std::make_pair(V, nullptr);
151 }
152
153 if (InsertElementInst *IEI = dyn_cast<InsertElementInst>(V)) {
154 // If this is an insert of an extract from some other vector, include it.
155 Value *VecOp = IEI->getOperand(0);
156 Value *ScalarOp = IEI->getOperand(1);
157 Value *IdxOp = IEI->getOperand(2);
158
159 if (ExtractElementInst *EI = dyn_cast<ExtractElementInst>(ScalarOp)) {
160 if (isa<ConstantInt>(EI->getOperand(1)) && isa<ConstantInt>(IdxOp)) {
161 unsigned ExtractedIdx =
162 cast<ConstantInt>(EI->getOperand(1))->getZExtValue();
163 unsigned InsertedIdx = cast<ConstantInt>(IdxOp)->getZExtValue();
164
165 // Either the extracted from or inserted into vector must be RHSVec,
166 // otherwise we'd end up with a shuffle of three inputs.
167 if (EI->getOperand(0) == PermittedRHS || PermittedRHS == nullptr) {
168 Value *RHS = EI->getOperand(0);
169 ShuffleOps LR = CollectShuffleElements(VecOp, Mask, RHS);
170 assert(LR.second == nullptr || LR.second == RHS);
171
172 if (LR.first->getType() != RHS->getType()) {
173 // We tried our best, but we can't find anything compatible with RHS
174 // further up the chain. Return a trivial shuffle.
175 for (unsigned i = 0; i < NumElts; ++i)
176 Mask[i] = ConstantInt::get(Type::getInt32Ty(V->getContext()), i);
177 return std::make_pair(V, nullptr);
178 }
179
180 unsigned NumLHSElts = RHS->getType()->getVectorNumElements();
181 Mask[InsertedIdx % NumElts] =
182 ConstantInt::get(Type::getInt32Ty(V->getContext()),
183 NumLHSElts+ExtractedIdx);
184 return std::make_pair(LR.first, RHS);
185 }
186
187 if (VecOp == PermittedRHS) {
188 // We've gone as far as we can: anything on the other side of the
189 // extractelement will already have been converted into a shuffle.
190 unsigned NumLHSElts =
191 EI->getOperand(0)->getType()->getVectorNumElements();
192 for (unsigned i = 0; i != NumElts; ++i)
193 Mask.push_back(ConstantInt::get(
194 Type::getInt32Ty(V->getContext()),
195 i == InsertedIdx ? ExtractedIdx : NumLHSElts + i));
196 return std::make_pair(EI->getOperand(0), PermittedRHS);
197 }
198
199 // If this insertelement is a chain that comes from exactly these two
200 // vectors, return the vector and the effective shuffle.
201 if (EI->getOperand(0)->getType() == PermittedRHS->getType() &&
202 CollectSingleShuffleElements(IEI, EI->getOperand(0), PermittedRHS,
203 Mask))
204 return std::make_pair(EI->getOperand(0), PermittedRHS);
205 }
206 }
207 }
208
209 // Otherwise, can't do anything fancy. Return an identity vector.
210 for (unsigned i = 0; i != NumElts; ++i)
211 Mask.push_back(ConstantInt::get(Type::getInt32Ty(V->getContext()), i));
212 return std::make_pair(V, nullptr);
213 }
214
215 // =============================================================================
216
217
218 namespace {
219
220 class BackendCanonicalize : public FunctionPass,
221 public InstVisitor<BackendCanonicalize, bool> {
222 public:
223 static char ID; // Pass identification, replacement for typeid
224 BackendCanonicalize() : FunctionPass(ID), DL(0), TLI(0) {
225 initializeBackendCanonicalizePass(*PassRegistry::getPassRegistry());
226 }
227 virtual void getAnalysisUsage(AnalysisUsage &AU) const {
228 AU.addRequired<DataLayoutPass>();
229 AU.addRequired<TargetLibraryInfo>();
230 FunctionPass::getAnalysisUsage(AU);
231 }
232
233 virtual bool runOnFunction(Function &F);
234
235 // InstVisitor implementation. Unhandled instructions stay as-is.
236 bool visitInstruction(Instruction &I) { return false; }
237 bool visitInsertElementInst(InsertElementInst &IE);
238 bool visitBitCastInst(BitCastInst &C);
239 bool visitLoadInst(LoadInst &L);
240
241 private:
242 const DataLayout *DL;
243 const TargetLibraryInfo *TLI;
244
245 // List of instructions that are now obsolete, and should be DCE'd.
246 typedef SmallVector<Instruction *, 512> KillList;
247 KillList Kill;
248
249 /// Helper that constant folds an instruction.
250 bool visitConstantFoldableInstruction(Instruction *I);
251
252 /// Empty the kill list, making sure that all other dead instructions
253 /// up the chain (but in the current basic block) also get killed.
254 static void emptyKillList(KillList &Kill);
255 };
256
257 } // anonymous namespace
258
259 char BackendCanonicalize::ID = 0;
260 INITIALIZE_PASS(BackendCanonicalize, "backend-canonicalize",
261 "Canonicalize PNaCl bitcode for LLVM backends", false, false)
262
263 bool BackendCanonicalize::runOnFunction(Function &F) {
264 bool Modified = false;
265 DL = &getAnalysis<DataLayoutPass>().getDataLayout();
266 TLI = &getAnalysis<TargetLibraryInfo>();
267
268 for (Function::iterator FI = F.begin(), FE = F.end(); FI != FE; ++FI)
269 for (BasicBlock::iterator BI = FI->begin(), BE = FI->end(); BI != BE; ++BI)
270 Modified |= visit(&*BI);
271 emptyKillList(Kill);
272 return Modified;
273 }
274
275 // This function is *almost* as-is from instcombine, avoiding silly
276 // cases that should already have been optimized.
277 bool BackendCanonicalize::visitInsertElementInst(InsertElementInst &IE) {
278 Value *ScalarOp = IE.getOperand(1);
279 Value *IdxOp = IE.getOperand(2);
280
281 // If the inserted element was extracted from some other vector, and if the
282 // indexes are constant, try to turn this into a shufflevector operation.
283 if (ExtractElementInst *EI = dyn_cast<ExtractElementInst>(ScalarOp)) {
284 if (isa<ConstantInt>(EI->getOperand(1)) && isa<ConstantInt>(IdxOp)) {
285 unsigned NumInsertVectorElts = IE.getType()->getNumElements();
286 unsigned NumExtractVectorElts =
287 EI->getOperand(0)->getType()->getVectorNumElements();
288 unsigned ExtractedIdx =
289 cast<ConstantInt>(EI->getOperand(1))->getZExtValue();
290 unsigned InsertedIdx = cast<ConstantInt>(IdxOp)->getZExtValue();
291
292 if (ExtractedIdx >= NumExtractVectorElts) // Out of range extract.
293 return false;
294
295 if (InsertedIdx >= NumInsertVectorElts) // Out of range insert.
296 return false;
297
298 // If this insertelement isn't used by some other insertelement, turn it
299 // (and any insertelements it points to), into one big shuffle.
300 if (!IE.hasOneUse() || !isa<InsertElementInst>(IE.user_back())) {
301 typedef SmallVector<Constant *, 16> MaskT;
302 MaskT Mask;
303 Value *LHS, *RHS;
304 std::tie(LHS, RHS) = CollectShuffleElements(&IE, Mask, nullptr);
305 if (!RHS)
306 RHS = UndefValue::get(LHS->getType());
307 // We now have a shuffle of LHS, RHS, Mask.
308
309 if (isa<UndefValue>(LHS) && !isa<UndefValue>(RHS)) {
310 // Canonicalize shufflevector to always have undef on the RHS,
311 // and adjust the mask.
312 std::swap(LHS, RHS);
313 for (MaskT::iterator I = Mask.begin(), E = Mask.end(); I != E; ++I) {
314 unsigned Idx = cast<ConstantInt>(*I)->getZExtValue();
315 unsigned NewIdx = Idx >= NumInsertVectorElts
316 ? Idx - NumInsertVectorElts
317 : Idx + NumInsertVectorElts;
318 *I = ConstantInt::get(Type::getInt32Ty(RHS->getContext()), NewIdx);
319 }
320 }
321
322 IRBuilder<> IRB(&IE);
323 IE.replaceAllUsesWith(
324 IRB.CreateShuffleVector(LHS, RHS, ConstantVector::get(Mask)));
325 // The chain of now-dead insertelement / extractelement
326 // instructions can be deleted.
327 Kill.push_back(&IE);
328
329 return true;
330 }
331 }
332 }
333
334 return false;
335 }
336
337 bool BackendCanonicalize::visitBitCastInst(BitCastInst &B) {
338 return visitConstantFoldableInstruction(&B);
339 }
340
341 bool BackendCanonicalize::visitLoadInst(LoadInst &L) {
342 return visitConstantFoldableInstruction(&L);
343 }
344
345 bool BackendCanonicalize::visitConstantFoldableInstruction(Instruction *I) {
346 if (Constant *Folded = ConstantFoldInstruction(I, DL, TLI)) {
347 I->replaceAllUsesWith(Folded);
348 Kill.push_back(I);
349 return true;
350 }
351 return false;
352 }
353
354 void BackendCanonicalize::emptyKillList(KillList &Kill) {
355 while (!Kill.empty())
356 RecursivelyDeleteTriviallyDeadInstructions(Kill.pop_back_val());
357 }
358
359 FunctionPass *llvm::createBackendCanonicalizePass() {
360 return new BackendCanonicalize();
361 }
OLDNEW
« no previous file with comments | « lib/Transforms/NaCl/AddPNaClExternalDecls.cpp ('k') | lib/Transforms/NaCl/CMakeLists.txt » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698