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

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

Issue 1423873002: PNaCl: Add a vector type legalization pass. Base URL: https://chromium.googlesource.com/native_client/pnacl-llvm.git@master
Patch Set: Created 5 years, 1 month 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
OLDNEW
(Empty)
1 //===-- VectorCanonicalizationPass.cpp - Canonicalize vector types --------===//
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 doesn't fix vectors in constants, other than those used directly by
11 // instructions.
12 // We don't expand ExtractValue/InsertValue (and can't), so ExpandStructRegs
13 // must be run before this one.
14 //
15 // The test generator can be found at
16 // https://github.com/DiamondLovesYou/pnacl-vector-canonicalization-test-generat or
17 //
18 //===----------------------------------------------------------------------===//
19
20 #include "llvm/InitializePasses.h"
21 #include "llvm/IR/Instructions.h"
22 #include "llvm/IR/Constants.h"
23 #include "llvm/IR/Function.h"
24 #include "llvm/IR/BasicBlock.h"
25 #include "llvm/IR/IRBuilder.h"
26 #include "llvm/IR/Module.h"
27 #include "llvm/IR/DebugInfo.h"
28 #include "llvm/IR/CFG.h"
29 #include "llvm/Transforms/Utils/Cloning.h"
30 #include "llvm/Transforms/Utils/ValueMapper.h"
31 #include "llvm/Transforms/NaCl.h"
32
33 #include <functional>
34 #include <deque>
35
36 template <typename T> T MinAlign(T left, T right) {
37 if (left == 0) {
38 return left;
39 } else {
40 return llvm::MinAlign(left, right);
41 }
42 }
43
44 using namespace llvm;
45
46 struct Strategy {
47 Strategy() = default;
48
49 inline operator bool() const { return To != From; }
50
51 VectorType *To = nullptr;
52 VectorType *From = nullptr;
53
54 inline unsigned toSliceStart(const unsigned I) const {
55 assert(To);
56 return I * To->getVectorNumElements();
57 }
58 inline unsigned toSliceEnd(const unsigned I,
59 const unsigned Max = ~0LL) const {
60 assert(To);
61 const auto Idx = (I + 1) * To->getVectorNumElements();
62 return std::min(Idx, Max);
63 }
64
65 /// Maps an element index to a split part index.
66 inline unsigned splitPart(const unsigned I) const {
67 if (!From || !To) {
68 return 0;
69 }
70
71 return I / To->getVectorNumElements();
72 }
73
74 inline unsigned fromElements() const {
75 if (!From) {
76 return 0;
77 } else {
78 return From->getVectorNumElements();
79 }
80 }
81 inline unsigned toElements() const {
82 if (!To) {
83 return 0;
84 } else {
85 return To->getVectorNumElements();
86 }
87 }
88
89 unsigned extra() const {
90 if (!*this) {
91 return 0;
92 } else {
93 assert(From);
94 assert(To);
95 return (From->getVectorNumElements() - 1) / To->getVectorNumElements();
96 }
97 }
98
99 unsigned values() const { return extra() + 1; }
100
101 bool split() const { return extra() != 0; }
102 bool expand() const { return *this && extra() == 0; }
103
104 // What number of elements is valid in the last part?
105 unsigned rem() const {
106 if (!*this) {
107 return 0;
108 }
109 if (fromElements() % toElements() == 0) {
110 return 0;
111 }
112
113 return fromElements() - extra() * toElements();
114 }
115 };
116
117 struct BitWidthMapper {
118 /// Bitwidths. Must be sorted ascending.
119 SmallVector<unsigned, 4> NormWidths;
120 /// Which `i1` element counts are allowed? Must be sorted ascending.
121 /// This must match `NormWidths`.
122 SmallVector<unsigned, 4> I1NumElements;
123
124 VectorType *mapType(VectorType *Ty, const DataLayout &DL) const {
125 Type *Inner = Ty->getScalarType();
126 if (Inner->isIntegerTy(1)) {
127 unsigned OldCount = Ty->getVectorNumElements();
128 unsigned NewCount = 0;
129 for (unsigned Count : I1NumElements) {
130 NewCount = Count;
131 if (OldCount == NewCount) {
132 return Ty;
133 } else if (NewCount < OldCount) {
134 continue;
135 } else {
136 break;
137 }
138 }
139
140 assert(NewCount != 0);
141 return VectorType::get(Inner, NewCount);
142 } else {
143 const unsigned BitWidth = DL.getTypeSizeInBits(Ty);
144
145 unsigned Width = 0;
146 for (unsigned I = 0; I < NormWidths.size(); ++I) {
147 Width = NormWidths[I];
148 if (Width < BitWidth) {
149 continue;
150 } else if (Width == BitWidth) {
151 return Ty;
152 } else {
153 break;
154 }
155 }
156
157 const auto InnerSize = DL.getTypeSizeInBits(Inner);
158 assert(Width != 0);
159 assert(Width % InnerSize == 0);
160 return VectorType::get(Inner, Width / InnerSize);
161 }
162 }
163
164 void getStrategy(Type *For, Strategy &Strat, const DataLayout &DL) const {
165 if (auto *VTy = dyn_cast<VectorType>(For)) {
166 auto *NewVTy = mapType(VTy, DL);
167 Strat.From = VTy;
168 Strat.To = NewVTy;
169 } else {
170 Strat.From = nullptr;
171 Strat.To = nullptr;
172 }
173 }
174 };
175
176 /// Helper to manage sets of allocas for use in split returns.
177 /// TODO use a maximally sized buffer for all return spaces.
178 struct ReturnAllocManager {
179 ReturnAllocManager(Instruction *InsertionPt) : Builder(InsertionPt) {}
180
181 const SmallVectorImpl<Value *> &get(const Strategy &S, const DataLayout &DL) {
182 assert(S);
183
184 auto I =
185 ScratchPads.insert(std::make_pair(S.To, SmallVector<Value *, 4>()));
186 auto &A = I.first->second;
187 for (unsigned I = A.size(); I < S.extra(); ++I) {
188 AllocaInst *Alloc = Builder.CreateAlloca(S.To);
189 Alloc->setAlignment(DL.getPrefTypeAlignment(S.To));
190 A.push_back(Alloc);
191 }
192
193 return A;
194 }
195
196 private:
197 IRBuilder<> Builder;
198 DenseMap<VectorType *, SmallVector<Value *, 4>> ScratchPads;
199 };
200
201 struct InstructionStrategy;
202 struct FunctionStrategy {
203 FunctionStrategy() {}
204 FunctionStrategy(const FunctionStrategy &rhs)
205 : Placeholders(rhs.Placeholders), Args(rhs.Args), Ret(rhs.Ret),
206 OldFTy(rhs.OldFTy), NewFTy(rhs.NewFTy) {}
207 FunctionStrategy(FunctionStrategy &&rhs)
208 : Placeholders(std::move(rhs.Placeholders)), Args(std::move(rhs.Args)),
209 Ret(std::move(rhs.Ret)), OldFTy(rhs.OldFTy), NewFTy(rhs.NewFTy) {}
210
211 FunctionStrategy &operator=(const FunctionStrategy &rhs) {
212 Args = rhs.Args;
213 Ret = rhs.Ret;
214
215 NewFTy = rhs.NewFTy;
216 OldFTy = rhs.OldFTy;
217
218 Placeholders = rhs.Placeholders;
219 return *this;
220 }
221 FunctionStrategy &operator=(FunctionStrategy &&rhs) {
222 Args = std::move(rhs.Args);
223 Ret = std::move(rhs.Ret);
224
225 NewFTy = rhs.NewFTy;
226 OldFTy = rhs.OldFTy;
227
228 Placeholders = std::move(rhs.Placeholders);
229 return *this;
230 }
231
232 inline operator bool() const { return OldFTy != NewFTy; }
233
234 /// Return an array of the new argument values. Some will be placeholders.
235 SmallVector<Value *, 8> mapFunction(Function::ArgumentListType &In) const;
236 void mapReturns(SmallVectorImpl<ReturnInst *> &Rets,
237 Function::ArgumentListType &Args, const DataLayout &DL) const;
238 void mapVaArg(VAArgInst *VaArg, const Strategy &Strategy,
239 IRBuilder<> &Builder) const;
240
241 AttributeSet mapAttrs(AttributeSet Old, LLVMContext &C,
242 const DataLayout &DL) const;
243
244 FunctionType *oldFunctionType() const { return OldFTy; }
245 FunctionType *newFunctionType() const { return NewFTy; }
246
247 void build(FunctionType *OldFTy, const BitWidthMapper &Map,
248 const DataLayout &DL);
249
250 const SmallVectorImpl<Strategy> &getArgs() const { return Args; }
251 const Strategy &getArg(const unsigned I) const { return Args[I]; }
252 const SmallVectorImpl<Argument *> &getPlaceholders() const {
253 return Placeholders;
254 }
255 const Strategy &getRet() const { return Ret; }
256
257 private:
258 SmallVector<Argument *, 8> Placeholders;
259 SmallVector<Strategy, 8> Args;
260 Strategy Ret;
261
262 FunctionType *OldFTy;
263 FunctionType *NewFTy;
264 };
265
266 /// This pass rewrites function signatures.
267 class VectorCanonicalizationFunctionPass {
268 public:
269 VectorCanonicalizationFunctionPass(BitWidthMapper &Cfg) : Cfg(Cfg) {}
270
271 void runOnModule(Module &M);
272
273 FunctionStrategy &buildStrategy(FunctionType *FTy, const DataLayout &DL) {
274 assert(FTy);
275
276 auto Result = Strategies.insert(std::make_pair(FTy, nullptr));
277 auto **Strategy = &Result.first->second;
278 if (Result.second) {
279 StrategyStorage.emplace_back();
280 *Strategy = &StrategyStorage.back();
281 (*Strategy)->build(FTy, Cfg, DL);
282 }
283
284 assert(*Strategy);
285 return **Strategy;
286 }
287
288 const FunctionStrategy &getOldFunctionStrategy(Function *F) {
289 auto R = FunToStrategy.find(F);
290 assert(R != FunToStrategy.end());
291 return *R->second;
292 }
293
294 void registerNewFunction(Function *F, FunctionStrategy &FS) {
295 const auto Inserted = FunToStrategy.insert(std::make_pair(F, &FS)).second;
296 (void)Inserted;
297 assert(Inserted);
298 }
299
300 bool modified() const { return Modified; }
301
302 private:
303 bool Modified = false;
304 BitWidthMapper &Cfg;
305
306 // avoids allocation on every new strategy.
307 std::deque<FunctionStrategy> StrategyStorage;
308
309 DenseMap<FunctionType *, FunctionStrategy *> Strategies;
310 DenseMap<Function *, FunctionStrategy *> FunToStrategy;
311 };
312
313 struct InstructionStrategy : public Strategy {
314 InstructionStrategy() = delete;
315 InstructionStrategy(Value *S) : Source(S) {}
316
317 Value *getValue(const unsigned I) const {
318 if (I > values()) {
319 return nullptr;
320 }
321 if (!*this) {
322 return Source;
323 }
324
325 return Expanded[I];
326 }
327 Value *getSource() const { return Source; }
328
329 const SmallVectorImpl<Value *> &getExpanded() const { return Expanded; }
330 SmallVectorImpl<Value *> &getExpanded() { return Expanded; }
331 void setExpanded(SmallVector<Value *, 4> Ex) {
332 assert(values() == Ex.size());
333 Expanded = std::move(Ex);
334 }
335 void setExpanded(Instruction *I) {
336 assert(values() == 1);
337 Expanded.clear();
338 Expanded.push_back(I);
339 }
340
341 void forEach(std::function<Value *()> Callback);
342 template <typename T>
343 void forEach(
344 ArrayRef<T> Elements,
345 std::function<Value *(const unsigned Count, ArrayRef<T> Slice)> Callback);
346 void forEach(std::function<Value *(const unsigned I, const unsigned Offset,
347 const unsigned End)> Callback);
348
349 private:
350 /// A constant or an instruction.
351 Value *Source = nullptr;
352
353 SmallVector<Value *, 2> Expanded;
354 };
355
356 class VectorCanonicalizationInstructionPass {
357 public:
358 VectorCanonicalizationInstructionPass() = delete;
359 VectorCanonicalizationInstructionPass(
360 Function *F, BitWidthMapper &Cfg,
361 VectorCanonicalizationFunctionPass &FPass)
362 : Cfg(Cfg), CallReturnAllocMgr(F->getEntryBlock().getFirstInsertionPt()),
363 FPass(FPass), FStrategy(FPass.getOldFunctionStrategy(F)),
364 DL(F->getParent()->getDataLayout()) {
365 // create instruction strategies for the placeholder values.
366 const auto &Placeholders = FStrategy.getPlaceholders();
367 auto NewArgsIt = F->arg_begin();
368 if (FStrategy.getRet()) {
369 // skip extra return arguments.
370 for (unsigned I = 0; I < FStrategy.getRet().extra(); ++I, ++NewArgsIt) {
371 }
372 }
373
374 for (unsigned I = 0; I < FStrategy.getArgs().size(); ++I) {
375 const auto &ArgStrategy = FStrategy.getArg(I);
376 if (!ArgStrategy) {
377 ++NewArgsIt;
378 continue;
379 }
380
381 auto *Placeholder = Placeholders[I];
382 assert(Placeholder);
383
384 auto &IStrategy =
385 Mapping.insert(std::make_pair(Placeholder,
386 InstructionStrategy(Placeholder)))
387 .first->second;
388 *static_cast<Strategy *>(&IStrategy) = FStrategy.getArg(I);
389 auto Callback = [&NewArgsIt]() mutable { return NewArgsIt++; };
390 IStrategy.forEach(std::move(Callback));
391 }
392 }
393
394 void runOnFunction(Function &F);
395
396 bool modified() const { return Modified; }
397
398 private:
399 bool Modified = false;
400
401 /// Breath-first.
402 void runOnBasicBlock(BasicBlock *BB, SmallPtrSetImpl<BasicBlock *> &Visited);
403 void runOnBasicBlockSuccessors(BasicBlock *BB,
404 SmallPtrSetImpl<BasicBlock *> &Visited);
405
406 const InstructionStrategy &findStrategyFor(Value *Source,
407 Instruction *InsertionPt) {
408 auto Result =
409 Mapping.insert(std::make_pair(Source, InstructionStrategy(Source)));
410 auto &IS = Result.first->second;
411 if (Result.second) {
412 buildStrategy(IS, InsertionPt);
413 }
414
415 return IS;
416 }
417 void fixStoreInstruction(StoreInst *OldStore);
418 void fixBitcastInstruction(BitCastInst *BC);
419 void fixExtractElementInstruction(ExtractElementInst *Extract);
420 void fixCallInstruction(CallInst *Call);
421 void fixShuffleInstruction(ShuffleVectorInst *Shuffle);
422 void fixCastInstruction(CastInst *Cast);
423 bool fixCmpInstruction(InstructionStrategy &Strategy, CmpInst *Cmp,
424 IRBuilder<> &Builder);
425
426 void fixPhiNodes();
427
428 void getShuffleValues(
429 const InstructionStrategy &LeftStrategy,
430 const InstructionStrategy &RightStrategy,
431 const SmallVectorImpl<int> &Mask,
432 SmallVectorImpl<std::tuple<Value *, Value *, unsigned>> &Values) const;
433 Value *shuffleRebuildHelper(
434 ShuffleVectorInst *Shuffle, IRBuilder<> &Builder,
435 SmallVectorImpl<std::tuple<Value *, Value *, unsigned>> &Values,
436 const unsigned Start, const unsigned End);
437
438 void buildStrategy(InstructionStrategy &Strategy, Instruction *InsertionPt);
439 void buildConstantStrategy(InstructionStrategy &Strategy, Constant *C,
440 IRBuilder<> &Builder);
441 void buildInstructionStrategy(InstructionStrategy &Strategy, Instruction *I,
442 IRBuilder<> &Builder);
443 void buildCastStrategy(InstructionStrategy &Strategy, CastInst *Cast,
444 IRBuilder<> &Builder);
445 void buildScalarCastStrategy(InstructionStrategy &Strategy, CastInst *Cast,
446 IRBuilder<> &Builder);
447 void buildVectorCastStrategy(InstructionStrategy &Strategy, CastInst *Cast,
448 IRBuilder<> &Builder);
449
450 BitWidthMapper &Cfg;
451 DenseMap<Value *, InstructionStrategy> Mapping;
452
453 ReturnAllocManager CallReturnAllocMgr;
454
455 SmallVector<InstructionStrategy, 32> PhiNodes;
456
457 SmallVector<Instruction *, 32> ToDelete;
458
459 VectorCanonicalizationFunctionPass &FPass;
460 const FunctionStrategy &FStrategy;
461
462 const DataLayout &DL;
463 };
464
465 void VectorCanonicalizationFunctionPass::runOnModule(Module &M) {
466 Modified = true;
467 SmallVector<Function *, 32> ToDelete;
468 auto &C = M.getContext();
469 const auto &DL = M.getDataLayout();
470
471 auto DISubprogramMap = makeSubprogramMap(M);
472
473 for (Module::iterator I = M.begin(); I != M.end(); ++I) {
474 Function *OldF = I;
475 auto &FStrategy = buildStrategy(OldF->getFunctionType(), DL);
476 if (!FStrategy) {
477 registerNewFunction(OldF, FStrategy);
478 continue;
479 }
480
481 Function *NewF =
482 Function::Create(FStrategy.newFunctionType(), OldF->getLinkage(), "");
483 registerNewFunction(NewF, FStrategy);
484 M.getFunctionList().insert(I, NewF);
485
486 auto OldAttrs = OldF->getAttributes();
487 auto NewAttrs = FStrategy.mapAttrs(OldAttrs, C, DL);
488 NewF->setAttributes(NewAttrs);
489
490 auto ParamMap = FStrategy.mapFunction(NewF->getArgumentList());
491
492 assert(ParamMap.size() == OldF->arg_size());
493
494 ValueToValueMapTy VMap;
495 {
496 auto OldArgIt = OldF->arg_begin();
497 for (unsigned J = 0; J < ParamMap.size(); ++J, ++OldArgIt) {
498 VMap[OldArgIt] = ParamMap[J];
499 }
500 }
501
502 SmallVector<ReturnInst *, 32> Returns;
503 CloneFunctionInto(NewF, OldF, VMap, false, Returns);
504
505 FStrategy.mapReturns(Returns, NewF->getArgumentList(), DL);
506 Returns.clear();
507
508 if (NewF->isVarArg()) {
509 for (auto &BB : NewF->getBasicBlockList()) {
510 for (auto &I : BB.getInstList()) {
511 if (auto *VAArg = dyn_cast<VAArgInst>(&I)) {
512 Strategy S;
513 Cfg.getStrategy(VAArg->getType(), S, DL);
514 IRBuilder<> Builder(VAArg);
515 FStrategy.mapVaArg(VAArg, S, Builder);
516 }
517 }
518 }
519 }
520
521 auto Found = DISubprogramMap.find(OldF);
522 if (Found != DISubprogramMap.end())
523 Found->second->replaceFunction(NewF);
524
525 OldF->replaceAllUsesWith(
526 ConstantExpr::getPointerCast(NewF, OldF->getType()));
527 ToDelete.push_back(OldF);
528
529 // This should be last:
530 NewF->takeName(OldF);
531 }
532
533 for (Function *F : ToDelete) {
534 F->dropAllReferences();
535 }
536 for (Function *F : ToDelete) {
537 F->eraseFromParent();
538 }
539 }
540
541 AttributeSet FunctionStrategy::mapAttrs(AttributeSet Old, LLVMContext &C,
542 const DataLayout &DL) const {
543 AttributeSet New;
544 New = New.addAttributes(C, AttributeSet::ReturnIndex, Old.getRetAttributes());
545 for (unsigned I = 0; I < Ret.extra(); ++I) {
546 New = New.addAttribute(C, 1 + I, Attribute::NonNull);
547 New = New.addAttribute(C, 1 + I, Attribute::NoCapture);
548 New = New.addDereferenceableAttr(C, I + 1, DL.getTypeAllocSize(Ret.To));
549 }
550 unsigned Offset = Ret.extra();
551
552 for (unsigned I = 0; I < Args.size(); ++I) {
553 const auto &Arg = Args[I];
554
555 const unsigned OldIndex = I + 1;
556 auto OldAttrs = Old.getParamAttributes(OldIndex);
557 if (OldAttrs.getNumSlots() == 0) {
558 Offset += Arg.extra();
559 continue;
560 }
561
562 unsigned OldSlot = 0;
563 for (; OldSlot < OldAttrs.getNumSlots(); ++OldSlot) {
564 if (OldAttrs.getSlotIndex(OldSlot) == OldIndex) {
565 break;
566 }
567 }
568 assert(OldSlot != OldAttrs.getNumSlots());
569
570 if (Arg) {
571 for (unsigned J = 0; J < Arg.values(); ++J) {
572 const auto NewIndex = 1 + I + J + Offset;
573 AttrBuilder B(AttributeSet(), NewIndex);
574 for (auto II = OldAttrs.begin(OldSlot), IE = OldAttrs.end(OldSlot);
575 II != IE; ++II) {
576 B.addAttribute(*II);
577 }
578 auto Attrs = AttributeSet::get(C, NewIndex, B);
579 New = New.addAttributes(C, NewIndex, Attrs);
580 }
581 Offset += Arg.extra();
582 } else {
583 const auto NewIndex = 1 + I + Offset;
584 AttrBuilder B(AttributeSet(), NewIndex);
585 for (auto II = OldAttrs.begin(OldSlot), IE = OldAttrs.end(OldSlot);
586 II != IE; ++II) {
587 B.addAttribute(*II);
588 }
589 auto Attrs = AttributeSet::get(C, NewIndex, B);
590 New = New.addAttributes(C, NewIndex, Attrs);
591 }
592 }
593
594 auto FnAttrs = Old.getFnAttributes();
595 if (Ret) {
596 FnAttrs = FnAttrs.removeAttribute(C, AttributeSet::FunctionIndex,
597 Attribute::ReadOnly);
598 }
599 New = New.addAttributes(C, AttributeSet::FunctionIndex, FnAttrs);
600
601 return New;
602 }
603
604 SmallVector<Value *, 8>
605 FunctionStrategy::mapFunction(Function::ArgumentListType &In) const {
606 SmallVector<Value *, 8> Out;
607
608 auto InArg = In.begin();
609
610 if (Ret) {
611 for (unsigned I = 0; I < Ret.extra(); ++I, ++InArg) {
612 }
613 }
614
615 for (unsigned I = 0; I < Args.size(); ++I) {
616 const auto &Result = Args[I];
617
618 if (!Result) {
619 Out.push_back(InArg);
620 } else {
621 Out.push_back(Placeholders[I]);
622 }
623
624 for (unsigned J = 0; J < Result.values(); ++J, ++InArg) {
625 }
626 }
627
628 return std::move(Out);
629 }
630 void FunctionStrategy::mapReturns(SmallVectorImpl<ReturnInst *> &Rets,
631 Function::ArgumentListType &Args,
632 const DataLayout &DL) const {
633 if (!Ret) {
634 return;
635 }
636
637 const unsigned NewCount = Ret.toElements();
638
639 SmallVector<int, 16> ShuffleIndices;
640 ShuffleIndices.resize(Ret.values() * NewCount);
641 for (unsigned I = 0; I < ShuffleIndices.size(); ++I) {
642 if (I < Ret.fromElements()) {
643 ShuffleIndices[I] = I;
644 } else {
645 ShuffleIndices[I] = Ret.fromElements() - 1;
646 }
647 }
648
649 Value *RightSide = UndefValue::get(Ret.From);
650 SmallVector<int, 16> NewMask;
651 for (ReturnInst *RetInst : Rets) {
652
653 Value *RetValue = RetInst->getReturnValue();
654
655 IRBuilder<> Builder(RetInst);
656
657 Value *NewRetValue = nullptr;
658 auto ArgIt = Args.begin();
659 for (unsigned I = 0; I < Ret.values(); ++I) {
660 ArrayRef<int> ShuffleIndicesRef = ShuffleIndices;
661 auto Slice = ShuffleIndicesRef.slice(I * NewCount, NewCount);
662 Value *Shuffle = Builder.CreateShuffleVector(RetValue, RightSide, Slice);
663 if (I == 0) {
664 NewRetValue = Shuffle;
665 continue;
666 } else {
667 Value *DestArg = &*ArgIt;
668 const unsigned Alignment = DL.getPrefTypeAlignment(Ret.To);
669 Builder.CreateAlignedStore(Shuffle, DestArg, Alignment);
670 }
671
672 ++ArgIt;
673 }
674
675 assert(NewRetValue);
676 Builder.CreateRet(NewRetValue);
677
678 RetInst->eraseFromParent();
679 }
680 }
681 void FunctionStrategy::mapVaArg(VAArgInst *VaArg, const Strategy &Strategy,
682 IRBuilder<> &Builder) const {
683 if (!Strategy) {
684 return;
685 }
686
687 // TODO
688 VaArg->dump();
689 llvm_unreachable("TODO mapVaArg");
690 }
691
692 void FunctionStrategy::build(FunctionType *OldFTy, const BitWidthMapper &Map,
693 const DataLayout &DL) {
694 this->OldFTy = OldFTy;
695 SmallVector<Type *, 8> NewArgs;
696
697 Type *RetTy = OldFTy->getReturnType();
698 Map.getStrategy(RetTy, Ret, DL);
699 for (unsigned I = 0; I < Ret.extra(); ++I) {
700 NewArgs.push_back(Ret.To->getPointerTo());
701 }
702 Type *NewRet = RetTy;
703 if (Ret) {
704 NewRet = Ret.To;
705 }
706
707 for (Type *ArgTy : OldFTy->params()) {
708 Strategy S;
709 Map.getStrategy(ArgTy, S, DL);
710 Args.push_back(S);
711 if (S) {
712 Argument *Placeholder = new Argument(S.From);
713 Placeholders.push_back(Placeholder);
714
715 for (unsigned I = 0; I < S.values(); ++I) {
716 NewArgs.push_back(S.To);
717 }
718 } else {
719 Placeholders.push_back(nullptr);
720 NewArgs.push_back(ArgTy);
721 }
722 }
723
724 this->NewFTy = FunctionType::get(NewRet, NewArgs, OldFTy->isVarArg());
725 }
726 void InstructionStrategy::forEach(std::function<Value *()> Callback) {
727 Expanded.clear();
728 Expanded.reserve(values());
729 for (unsigned I = 0; I < values(); ++I) {
730 Value *V = Callback();
731 assert(V);
732 Expanded.push_back(V);
733 }
734 }
735 template <typename T>
736 void InstructionStrategy::forEach(
737 ArrayRef<T> Elements,
738 std::function<Value *(const unsigned Count, ArrayRef<T> Slice)> Callback) {
739 Expanded.clear();
740 Expanded.reserve(values());
741
742 const auto Per = To->getVectorNumElements();
743 for (unsigned I = 0; I < values(); ++I) {
744 const auto Start = Per * I;
745 const auto End = Per * (I + 1);
746
747 auto Slice = Elements.slice(Start, std::min((size_t)End, Elements.size()));
748
749 Value *V;
750 if (End > Elements.size()) {
751 // We must copy from the last element because otherwise we could introduce
752 // div by zero etc.
753 SmallVector<T, 8> NewSlice(Slice.begin(), Slice.end());
754 for (unsigned I = Slice.size(); I < End; ++I) {
755 NewSlice.push_back(Slice.back());
756 }
757 V = Callback(Per, NewSlice);
758 } else {
759 V = Callback(Per, Slice);
760 }
761 assert(V);
762 Expanded.push_back(V);
763 }
764 }
765 void InstructionStrategy::forEach(std::function<Value *(
766 const unsigned I, const unsigned Offset, const unsigned End)> Callback) {
767 Expanded.clear();
768 Expanded.reserve(values());
769
770 const auto Per = To->getVectorNumElements();
771 for (unsigned I = 0; I < values(); ++I) {
772 const auto Start = Per * I;
773 const auto End = Per * (I + 1);
774
775 Value *V = Callback(I, Start, End);
776 assert(V);
777 Expanded.push_back(V);
778 }
779 }
780 void VectorCanonicalizationInstructionPass::runOnFunction(Function &F) {
781 SmallPtrSet<BasicBlock *, 64> Visited;
782 BasicBlock *Entry = &F.getEntryBlock();
783
784 runOnBasicBlock(Entry, Visited);
785 runOnBasicBlockSuccessors(Entry, Visited);
786
787 fixPhiNodes();
788
789 for (auto *I : ToDelete) {
790 I->dropAllReferences();
791 }
792 for (auto *I : ToDelete) {
793 I->eraseFromParent();
794 }
795 ToDelete.clear();
796 }
797
798 void VectorCanonicalizationInstructionPass::runOnBasicBlock(
799 BasicBlock *BB, SmallPtrSetImpl<BasicBlock *> &Visited) {
800 for (auto II = BB->begin(); II != BB->end();) {
801 auto I = II++;
802 const auto &Strategy = findStrategyFor(&*I, &*I);
803 /// We still need to fix cases where the instruction doesn't itself require
804 /// promotion, but one of its operands does (or was).
805 if (Strategy) {
806 // We don't need to do this for things already fixed.
807 continue;
808 }
809
810 const auto Opcode = I->getOpcode();
811 if (Opcode == Instruction::BitCast &&
812 findStrategyFor(I->getOperand(0), &*I)) {
813 /// ie: `bitcast <8 x i32> to i256`
814 fixBitcastInstruction(cast<BitCastInst>(&*I));
815 } else if (Opcode == Instruction::Call) {
816 fixCallInstruction(cast<CallInst>(&*I));
817 } else if (Opcode == Instruction::ShuffleVector) {
818 fixShuffleInstruction(cast<ShuffleVectorInst>(&*I));
819 } else if (Opcode == Instruction::ExtractElement) {
820 fixExtractElementInstruction(cast<ExtractElementInst>(&*I));
821 } else if (Opcode == Instruction::Store) {
822 fixStoreInstruction(cast<StoreInst>(&*I));
823 } else if (auto *Cast = dyn_cast<CastInst>(&*I)) {
824 fixCastInstruction(Cast);
825 } else if (auto *Cmp = dyn_cast<CmpInst>(&*I)) {
826 IRBuilder<> Builder(Cmp);
827 if (fixCmpInstruction(Mapping.find(I)->second, Cmp, Builder)) {
828 ToDelete.push_back(Cmp);
829 }
830 }
831 }
832 }
833 void VectorCanonicalizationInstructionPass::runOnBasicBlockSuccessors(
834 BasicBlock *BB, SmallPtrSetImpl<BasicBlock *> &Visited) {
835 if (!Visited.insert(BB).second) {
836 return;
837 }
838
839 for (BasicBlock *Successor : successors(BB)) {
840 runOnBasicBlock(Successor, Visited);
841 }
842
843 for (BasicBlock *Successor : successors(BB)) {
844 runOnBasicBlockSuccessors(Successor, Visited);
845 }
846 }
847 void VectorCanonicalizationInstructionPass::buildStrategy(
848 InstructionStrategy &Strategy, Instruction *InsertionPt) {
849
850 auto *S = Strategy.getSource();
851 Cfg.getStrategy(S->getType(), Strategy, DL);
852
853 if (!Strategy) {
854 return;
855 }
856
857 Modified = true;
858
859 IRBuilder<> Builder(InsertionPt);
860
861 if (auto *C = dyn_cast<Constant>(S)) {
862 buildConstantStrategy(Strategy, C, Builder);
863 } else if (auto *I = dyn_cast<Instruction>(S)) {
864 buildInstructionStrategy(Strategy, I, Builder);
865 ToDelete.push_back(I);
866 } else {
867 S->dump();
868 llvm_unreachable("woa");
869 }
870 }
871
872 template <typename T, bool Valid = std::is_floating_point<T>::value ||
873 std::is_integral<T>::value>
874 struct GetData;
875
876 template <typename T> struct GetData<T, true> {
877 LLVMContext &C;
878 SmallVector<T, 8> Data;
879
880 GetData(ConstantDataSequential *SeqData) : C(SeqData->getContext()) {
881 Data.clear();
882 const auto NumElements = SeqData->getNumElements();
883
884 Data.reserve(NumElements);
885
886 for (unsigned I = 0; I < NumElements; ++I) {
887 if (std::is_integral<T>::value) {
888 const uint64_t Value = SeqData->getElementAsInteger(I);
889 Data.push_back(static_cast<T>(Value));
890 } else if (std::is_same<T, float>::value) {
891 const auto Float = SeqData->getElementAsFloat(I);
892 Data.push_back(Float);
893 } else if (std::is_same<T, double>::value) {
894 const auto Double = SeqData->getElementAsDouble(I);
895 Data.push_back(Double);
896 }
897 }
898 }
899
900 void forEach(InstructionStrategy &Strategy) const {
901 std::function<Value *(const unsigned, ArrayRef<T>)> Callback =
902 [this](const unsigned Count, ArrayRef<T> Slice) {
903 return ConstantDataVector::get(this->C, Slice);
904 };
905 Strategy.forEach(ArrayRef<T>(Data), std::move(Callback));
906 }
907 };
908
909 void VectorCanonicalizationInstructionPass::buildConstantStrategy(
910 InstructionStrategy &Strategy, Constant *C, IRBuilder<> &Builder) {
911 /// Expand these first four directly.
912 if (isa<ConstantAggregateZero>(C)) {
913 auto *VTy = Strategy.To;
914 auto Callback = [VTy]() { return ConstantAggregateZero::get(VTy); };
915 Strategy.forEach(std::move(Callback));
916 } else if (isa<UndefValue>(C)) {
917 auto *VTy = Strategy.To;
918 auto Callback = [VTy]() { return UndefValue::get(VTy); };
919 Strategy.forEach(std::move(Callback));
920 } else if (auto *Data = dyn_cast<ConstantDataVector>(C)) {
921 /// Well this is awful.
922 Type *ElementType = Data->getElementType();
923 std::function<void()> Run;
924 if (ElementType->isIntegerTy(8)) {
925 auto GD = GetData<uint8_t>(Data);
926 Run = [GD, &Strategy]() { GD.forEach(Strategy); };
927 } else if (ElementType->isIntegerTy(16)) {
928 auto GD = GetData<uint16_t>(Data);
929 Run = [GD, &Strategy]() { GD.forEach(Strategy); };
930 } else if (ElementType->isIntegerTy(32)) {
931 auto GD = GetData<uint32_t>(Data);
932 Run = [GD, &Strategy]() { GD.forEach(Strategy); };
933 } else if (ElementType->isIntegerTy(64)) {
934 auto GD = GetData<uint64_t>(Data);
935 Run = [GD, &Strategy]() { GD.forEach(Strategy); };
936 } else if (ElementType->isFloatTy()) {
937 auto GD = GetData<float>(Data);
938 Run = [GD, &Strategy]() { GD.forEach(Strategy); };
939 } else if (ElementType->isDoubleTy()) {
940 auto GD = GetData<double>(Data);
941 Run = [GD, &Strategy]() { GD.forEach(Strategy); };
942 } else {
943 Data->dump();
944 llvm_unreachable("unknown sequential type");
945 }
946
947 assert(Run);
948 Run();
949 } else if (auto *Data = dyn_cast<ConstantVector>(C)) {
950 SmallVector<Constant *, 8> Operands;
951 Operands.reserve(Data->getType()->getNumElements());
952 for (auto *Element : Data->operand_values()) {
953 Operands.push_back(cast<Constant>(Element));
954 }
955 std::function<Value *(const unsigned, ArrayRef<Constant *>)> Callback =
956 [](const unsigned, ArrayRef<Constant *> Slice) {
957 return ConstantVector::get(Slice);
958 };
959 Strategy.forEach(ArrayRef<Constant *>(Operands), std::move(Callback));
960 } else if (auto *Expr = dyn_cast<ConstantExpr>(C)) {
961 /// Use shuffle to split these.
962 const unsigned NumElements = Expr->getType()->getVectorNumElements();
963 Constant *Undef = UndefValue::get(Expr->getType());
964 IntegerType *I32Ty = Type::getInt32Ty(Expr->getContext());
965 auto Callback = [Expr, NumElements, Undef, I32Ty, &Strategy](
966 const unsigned, const unsigned Offset, const unsigned End) mutable {
967 SmallVector<Constant *, 8> MaskValues;
968 MaskValues.resize(End - Offset);
969 for (unsigned I = 0; I < MaskValues.size(); ++I) {
970 unsigned V;
971 if (I > NumElements) {
972 V = NumElements;
973 } else {
974 V = Offset + I;
975 }
976
977 MaskValues[I] = ConstantInt::get(I32Ty, V);
978 }
979
980 auto *Mask = ConstantVector::get(MaskValues);
981 Constant *C =
982 ConstantExpr::getShuffleVector(Expr, Undef, Mask, Strategy.To);
983 assert(C);
984 return C;
985 };
986 Strategy.forEach(std::move(Callback));
987 } else {
988 C->dump();
989 llvm_unreachable("constant not handled");
990 }
991 }
992 void VectorCanonicalizationInstructionPass::buildInstructionStrategy(
993 InstructionStrategy &Strategy, Instruction *I, IRBuilder<> &Builder) {
994 if (auto *Load = dyn_cast<LoadInst>(I)) {
995 /// Split up the load.
996 assert(!Load->isAtomic() && "Atomic loading vectors isn't supported" &&
997 "TODO?");
998
999 const auto &Source = findStrategyFor(Load->getPointerOperand(), Load);
1000 assert(Source.values() == 1);
1001
1002 const unsigned FromLen = Load->getType()->getVectorNumElements();
1003 const unsigned OriginalAlignment = Load->getAlignment();
1004 const unsigned ElementByteWidth =
1005 DL.getTypeSizeInBits(Load->getType()->getVectorElementType()) / 8;
1006 auto *I32Ty = IntegerType::get(I->getContext(), 32);
1007 auto Callback = [Load, &Source, &Builder, FromLen, ElementByteWidth,
1008 OriginalAlignment, &Strategy, I32Ty](
1009 const unsigned Part, const unsigned Offset, const unsigned End) {
1010 Value *Expanded = nullptr;
1011 if (FromLen < End) {
1012 Value *Chain = UndefValue::get(Strategy.To);
1013 // Don't load past the end of the vector.
1014 for (unsigned I = 0; I + Offset < std::min(End, FromLen); ++I) {
1015 // gep -> scalar load -> insert element
1016 ArrayRef<uint64_t> Indices = {0, I + Offset};
1017 Type *IndexedType = GetElementPtrInst::getIndexedType(
1018 Source.getSource()->getType(), Indices);
1019 auto *GEP = Builder.CreateConstGEP2_32(
1020 IndexedType, Source.getValue(0), 0, I + Offset);
1021 const unsigned Alignment =
1022 MinAlign(OriginalAlignment, ElementByteWidth * (Offset + I));
1023 auto *NewLoad =
1024 Builder.CreateAlignedLoad(GEP, Alignment, Load->isVolatile());
1025 Chain = Builder.CreateInsertElement(Chain, NewLoad,
1026 ConstantInt::get(I32Ty, I));
1027 }
1028
1029 Expanded = Chain;
1030 } else {
1031 // gep -> bitcast to vector type -> load
1032 ArrayRef<uint64_t> Indices = {0, Offset};
1033 Type *IndexedType = GetElementPtrInst::getIndexedType(
1034 Source.getSource()->getType(), Indices);
1035 auto *GEP = Builder.CreateConstGEP2_32(IndexedType, Source.getValue(0),
1036 0, Offset);
1037 auto *BC = Builder.CreatePointerCast(GEP, Strategy.To->getPointerTo());
1038 const unsigned Alignment =
1039 MinAlign(OriginalAlignment, ElementByteWidth * Offset);
1040 Expanded = Builder.CreateAlignedLoad(BC, Alignment, Load->isVolatile());
1041 }
1042 return Expanded;
1043 };
1044 Strategy.forEach(std::move(Callback));
1045 } else if (auto *Insert = dyn_cast<InsertElementInst>(I)) {
1046 // No need to lookup the inserted value's strategy; it must be a scalar
1047 // anyway.
1048 auto *InsertedValue = Insert->getOperand(1);
1049 const auto &SourceStrategy = findStrategyFor(Insert->getOperand(0), Insert);
1050 auto *OriginalIdx = Insert->getOperand(2);
1051 auto *I32Ty = IntegerType::get(I->getContext(), 32);
1052
1053 if (isa<ConstantInt>(OriginalIdx) || SourceStrategy.extra() == 0) {
1054 auto *CIdx = dyn_cast<ConstantInt>(OriginalIdx);
1055 auto Callback =
1056 [InsertedValue, &SourceStrategy, CIdx, &Builder, I32Ty, OriginalIdx](
1057 const unsigned I, const unsigned Start, const unsigned End) {
1058 Value *NewIdx = nullptr;
1059 auto *Source = SourceStrategy.getValue(I);
1060 if (CIdx) {
1061 const auto Idx = CIdx->getZExtValue();
1062 if (Start <= Idx &&
1063 Idx < std::min(End, SourceStrategy.fromElements())) {
1064 NewIdx = ConstantInt::get(I32Ty, Idx - Start);
1065 } else {
1066 return Source;
1067 }
1068 } else {
1069 assert(I == 0);
1070 NewIdx = OriginalIdx;
1071 }
1072 assert(NewIdx);
1073 return Builder.CreateInsertElement(Source, InsertedValue, NewIdx);
1074 };
1075 Strategy.forEach(std::move(Callback));
1076 } else {
1077 /// Create a chain of selects on integer cmps on each index
1078 /// Each chain iteration will insert the new value into a temp and then
1079 /// select on an ICmp with the uninserted value.
1080 /// TODO create a pass the recreate the original variable
1081 /// InsertElementInst on the llc side.
1082
1083 auto Callback =
1084 [OriginalIdx, &Builder, InsertedValue, &SourceStrategy, I32Ty](
1085 const unsigned I, const unsigned Start, const unsigned End) {
1086 Value *Source = SourceStrategy.getValue(I);
1087 Value *Last = Source;
1088 for (unsigned PartIdx = Start;
1089 PartIdx < std::min(End, SourceStrategy.fromElements());
1090 ++PartIdx) {
1091
1092 Value *CPartIdx = ConstantInt::get(I32Ty, PartIdx - Start);
1093 Value *Inserted =
1094 Builder.CreateInsertElement(Last, InsertedValue, CPartIdx);
1095 Value *OriginalIdxConst =
1096 ConstantInt::get(OriginalIdx->getType(), PartIdx);
1097 Value *ICmp = Builder.CreateICmp(CmpInst::ICMP_EQ,
1098 OriginalIdxConst, OriginalIdx);
1099 Value *Select = Builder.CreateSelect(ICmp, Inserted, Last);
1100 Last = Select;
1101 }
1102 return Last;
1103 };
1104 Strategy.forEach(std::move(Callback));
1105 }
1106 } else if (isa<PHINode>(I)) {
1107 /// Generate placeholder phis. After we've finished going over the function,
1108 /// we go over all the phis and insert the predecessor block and values.
1109 auto *VTy = Strategy.To;
1110 auto Callback = [&Builder, VTy]() { return Builder.CreatePHI(VTy, 0); };
1111 Strategy.forEach(std::move(Callback));
1112 PhiNodes.push_back(Strategy);
1113 } else if (auto *Cast = dyn_cast<CastInst>(I)) {
1114 buildCastStrategy(Strategy, Cast, Builder);
1115 } else if (auto *Shuffle = dyn_cast<ShuffleVectorInst>(I)) {
1116 SmallVector<std::tuple<Value *, Value *, unsigned>, 16> Values;
1117
1118 const auto Mask = Shuffle->getShuffleMask();
1119 const auto &LeftStrategy = findStrategyFor(Shuffle->getOperand(0), Shuffle);
1120 const auto &RightStrategy =
1121 findStrategyFor(Shuffle->getOperand(1), Shuffle);
1122 assert(LeftStrategy.To == RightStrategy.To);
1123
1124 getShuffleValues(LeftStrategy, RightStrategy, Mask, Values);
1125
1126 auto Callback = [&Values, this, Shuffle, &Builder](
1127 const unsigned, const unsigned Start, const unsigned End) {
1128 return this->shuffleRebuildHelper(Shuffle, Builder, Values, Start, End);
1129 };
1130 Strategy.forEach(std::move(Callback));
1131 } else if (auto *Call = dyn_cast<CallInst>(I)) {
1132 // Fix the return and arguments.
1133 auto &C = I->getContext();
1134 const DataLayout &DL = I->getParent()->getModule()->getDataLayout();
1135
1136 Value *Called = Call->getCalledValue();
1137 auto *FTy = cast<FunctionType>(Called->getType()->getContainedType(0));
1138 const auto &FStrategy = FPass.buildStrategy(FTy, DL);
1139
1140 SmallVector<Value *, 8> NewArgs;
1141 ArrayRef<Value *> RetSpace;
1142 assert(FStrategy.getRet());
1143 assert(FStrategy.getRet().extra() == Strategy.extra());
1144 RetSpace = CallReturnAllocMgr.get(FStrategy.getRet(), DL);
1145 for (unsigned I = 0; I < FStrategy.getRet().extra(); ++I) {
1146 NewArgs.push_back(RetSpace[I]);
1147 }
1148
1149 unsigned ArgIt = 0;
1150 for (const auto &ArgS : FStrategy.getArgs()) {
1151 Value *Arg = Call->getArgOperand(ArgIt++);
1152 if (!ArgS) {
1153 NewArgs.push_back(Arg);
1154 continue;
1155 }
1156
1157 const auto &Strategy = findStrategyFor(Arg, Call);
1158 for (unsigned I = 0; I < Strategy.values(); ++I) {
1159 NewArgs.push_back(Strategy.getValue(I));
1160 }
1161 }
1162
1163 Called = Builder.CreatePointerCast(
1164 Called, FStrategy.newFunctionType()->getPointerTo());
1165
1166 auto Callback = [&FStrategy, &Builder, &NewArgs, RetSpace, Called, &C, &DL,
1167 Call, &Strategy](const unsigned Part, const unsigned,
1168 const unsigned) -> Value *{
1169 if (Part == 0) {
1170 CallInst *NewCall = Builder.CreateCall(Called, NewArgs);
1171 NewCall->setAttributes(
1172 FStrategy.mapAttrs(Call->getAttributes(), C, DL));
1173 return NewCall;
1174 } else {
1175 const unsigned Alignment = DL.getPrefTypeAlignment(Strategy.To);
1176 return Builder.CreateAlignedLoad(RetSpace[Part - 1], Alignment);
1177 }
1178 };
1179 Strategy.forEach(std::move(Callback));
1180 } else if (auto *Bin = dyn_cast<BinaryOperator>(I)) {
1181 const auto Opcode = Bin->getOpcode();
1182 const auto &Left = findStrategyFor(Bin->getOperand(0), Bin);
1183 const auto &Right = findStrategyFor(Bin->getOperand(1), Bin);
1184
1185 auto Callback = [Opcode, &Left, &Right, &Builder, Bin](
1186 const unsigned Part, const unsigned, const unsigned) {
1187 Value *NewPart = Builder.CreateBinOp(Opcode, Left.getValue(Part),
1188 Right.getValue(Part));
1189 if (auto *NewBin = dyn_cast<BinaryOperator>(NewPart)) {
1190 NewBin->copyIRFlags(Bin);
1191 }
1192 return NewPart;
1193 };
1194 Strategy.forEach(std::move(Callback));
1195 } else if (auto *Cmp = dyn_cast<CmpInst>(I)) {
1196 const auto Fixed = fixCmpInstruction(Strategy, Cmp, Builder);
1197 (void)Fixed;
1198 assert(Fixed);
1199 } else if (auto *Select = dyn_cast<SelectInst>(I)) {
1200 const auto &Cmp = findStrategyFor(Select->getOperand(0), Select);
1201 const auto &Left = findStrategyFor(Select->getOperand(1), Select);
1202 const auto &Right = findStrategyFor(Select->getOperand(2), Select);
1203
1204 auto Callback = [&Builder, &Cmp, &Left, &Right](
1205 const unsigned Part, const unsigned, const unsigned) {
1206 return Builder.CreateSelect(Cmp.getValue(Part), Left.getValue(Part),
1207 Right.getValue(Part));
1208 };
1209 Strategy.forEach(std::move(Callback));
1210 } else {
1211 I->dump();
1212 llvm_unreachable("unhandled instruction");
1213 }
1214 }
1215
1216 void VectorCanonicalizationInstructionPass::buildCastStrategy(
1217 InstructionStrategy &Strategy, CastInst *Cast, IRBuilder<> &Builder) {
1218 /// Excluding bitcasts and casts that keep the overall vector size constant,
1219 /// we have to perform the cast on each element of the vector, and then
1220 /// recreate the result vector.
1221 /// TODO when the expanded type is still legal, but not the same size.
1222 /// I've omitted ^ because PNaCl doesn't support more than one vector width
1223 /// anyway.
1224 auto *FromTy = Cast->getOperand(0)->getType();
1225 const auto Opcode = Cast->getOpcode();
1226 switch (Opcode) {
1227 default:
1228 Cast->dump();
1229 llvm_unreachable("unhandled cast instruction");
1230 case Instruction::BitCast: {
1231 if (FromTy->isVectorTy()) {
1232 buildVectorCastStrategy(Strategy, Cast, Builder);
1233 } else {
1234 Cast->dump();
1235 llvm_unreachable("unhandled bitcast (non vector -> vector). TODO?");
1236 }
1237 break;
1238 }
1239 case Instruction::IntToPtr:
1240 case Instruction::PtrToInt:
1241 case Instruction::FPToUI:
1242 case Instruction::FPToSI:
1243 case Instruction::UIToFP:
1244 case Instruction::SIToFP: {
1245 const auto SourceSize = DL.getTypeSizeInBits(FromTy);
1246 const auto DestSize = DL.getTypeSizeInBits(Cast->getType());
1247 if (SourceSize == DestSize) {
1248 buildVectorCastStrategy(Strategy, Cast, Builder);
1249 } else {
1250 buildScalarCastStrategy(Strategy, Cast, Builder);
1251 }
1252
1253 break;
1254 }
1255 case Instruction::Trunc:
1256 case Instruction::ZExt:
1257 case Instruction::SExt: {
1258 buildScalarCastStrategy(Strategy, Cast, Builder);
1259 break;
1260 }
1261 }
1262 }
1263 void VectorCanonicalizationInstructionPass::buildScalarCastStrategy(
1264 InstructionStrategy &Strategy, CastInst *Cast, IRBuilder<> &Builder) {
1265 const auto &SourceStrategy = findStrategyFor(Cast->getOperand(0), Cast);
1266 const auto Opcode = Cast->getOpcode();
1267 auto *ToVTy = Strategy.To;
1268 auto *ToElementTy = ToVTy->getElementType();
1269 auto *I32Ty = IntegerType::get(Cast->getContext(), 32);
1270 auto Callback =
1271 [Opcode, &SourceStrategy, &Strategy, &Builder, ToVTy, ToElementTy, I32Ty](
1272 const unsigned Part, const unsigned Start, const unsigned End) {
1273 Value *Inserted = UndefValue::get(ToVTy);
1274 for (unsigned I = Start; I < std::min(End, Strategy.fromElements());
1275 ++I) {
1276 const auto SourcePart = SourceStrategy.splitPart(I);
1277 Value *Source = SourceStrategy.getValue(SourcePart);
1278 auto *ExtractIdx = ConstantInt::get(
1279 I32Ty, I - SourceStrategy.toSliceStart(SourcePart));
1280 Value *Extracted = Builder.CreateExtractElement(Source, ExtractIdx);
1281 Value *Casted = Builder.CreateCast(Opcode, Extracted, ToElementTy);
1282 Inserted = Builder.CreateInsertElement(
1283 Inserted, Casted, ConstantInt::get(I32Ty, I - Start));
1284 }
1285
1286 return Inserted;
1287 };
1288 Strategy.forEach(std::move(Callback));
1289 }
1290 void VectorCanonicalizationInstructionPass::buildVectorCastStrategy(
1291 InstructionStrategy &Strategy, CastInst *Cast, IRBuilder<> &Builder) {
1292 const auto &SourceStrategy = findStrategyFor(Cast->getOperand(0), Cast);
1293 const auto Opcode = Cast->getOpcode();
1294 auto *ToVTy = Strategy.To;
1295
1296 auto Callback = [Opcode, &SourceStrategy, &Builder, ToVTy](
1297 const unsigned Part, const unsigned, const unsigned) {
1298 Value *Source = SourceStrategy.getValue(Part);
1299 return Builder.CreateCast(Opcode, Source, ToVTy);
1300 };
1301 Strategy.forEach(std::move(Callback));
1302 }
1303 void VectorCanonicalizationInstructionPass::fixStoreInstruction(
1304 StoreInst *OldStore) {
1305
1306 Value *Src = OldStore->getValueOperand();
1307 const auto &ValueStrategy = findStrategyFor(Src, OldStore);
1308 if (!ValueStrategy) {
1309 return;
1310 }
1311
1312 /// Split up the store.
1313 assert(!OldStore->isAtomic() && "Atomic vectors aren't supported" && "TODO?");
1314
1315 IRBuilder<> Builder(OldStore);
1316
1317 Value *Dest = OldStore->getPointerOperand();
1318
1319 const unsigned OriginalAlignment = OldStore->getAlignment();
1320
1321 auto *I32Ty = IntegerType::get(OldStore->getContext(), 32);
1322 const unsigned ElementByteWidth =
1323 DL.getTypeSizeInBits(Src->getType()->getVectorElementType()) / 8;
1324
1325 const auto Rem = ValueStrategy.rem();
1326
1327 unsigned Parts;
1328 if (Rem == 0) {
1329 Parts = ValueStrategy.values();
1330 } else {
1331 Parts = ValueStrategy.extra();
1332 }
1333 for (unsigned Part = 0; Part < Parts; ++Part) {
1334 const uint64_t Start = ValueStrategy.toSliceStart(Part);
1335 Value *PartValue = ValueStrategy.getValue(Part);
1336
1337 // gep -> bitcast to vector type -> store
1338 ArrayRef<uint64_t> Indices = {0, Start};
1339 Type *IndexedType =
1340 GetElementPtrInst::getIndexedType(Dest->getType(), Indices);
1341 auto *GEP = Builder.CreateConstGEP2_32(IndexedType, Dest, 0, Start);
1342 auto *BC = Builder.CreatePointerCast(GEP, ValueStrategy.To->getPointerTo());
1343
1344 const unsigned Alignment =
1345 MinAlign(OriginalAlignment, ElementByteWidth * Start);
1346 Builder.CreateAlignedStore(PartValue, BC, Alignment,
1347 OldStore->isVolatile());
1348 }
1349
1350 if (Rem != 0) {
1351 const auto Part = ValueStrategy.extra();
1352 Value *PartValue = ValueStrategy.getValue(Part);
1353 const uint64_t Start = ValueStrategy.toSliceStart(Part);
1354 for (unsigned PartIdx = 0; PartIdx < Rem; ++PartIdx) {
1355 // Don't store past the end of the vector.
1356 // gep -> scalar store
1357 ArrayRef<uint64_t> Indices = {0, PartIdx + Start};
1358 Type *IndexedType =
1359 GetElementPtrInst::getIndexedType(Dest->getType(), Indices);
1360 auto *GEP =
1361 Builder.CreateConstGEP2_32(IndexedType, Dest, 0, PartIdx + Start);
1362 auto *CPartIdx = ConstantInt::get(I32Ty, PartIdx);
1363 Value *Extracted = Builder.CreateExtractElement(PartValue, CPartIdx);
1364
1365 const unsigned Alignment =
1366 MinAlign(OriginalAlignment, ElementByteWidth * (PartIdx + Start));
1367 Builder.CreateAlignedStore(Extracted, GEP, Alignment,
1368 OldStore->isVolatile());
1369 }
1370 }
1371
1372 ToDelete.push_back(OldStore);
1373 }
1374 void VectorCanonicalizationInstructionPass::fixBitcastInstruction(
1375 BitCastInst *BC) {
1376 // ie: `bitcast <6 x i32> to i196` or some such awkwardness.
1377
1378 BC->dump();
1379 llvm_unreachable("unhandled vector bitcast. TODO");
1380 }
1381 void VectorCanonicalizationInstructionPass::fixExtractElementInstruction(
1382 ExtractElementInst *Extract) {
1383 Value *Extracted = nullptr;
1384 const auto &SourceStrategy = findStrategyFor(Extract->getOperand(0), Extract);
1385 if (!SourceStrategy) {
1386 return;
1387 }
1388
1389 IRBuilder<> Builder(Extract);
1390 auto *I32Ty = IntegerType::get(Extract->getContext(), 32);
1391
1392 auto *OriginalIdx = Extract->getOperand(1);
1393
1394 if (isa<ConstantInt>(OriginalIdx) || SourceStrategy.extra() == 0) {
1395 Value *NewIdx = nullptr;
1396 Value *Source = nullptr;
1397 if (auto *CIdx = dyn_cast<ConstantInt>(OriginalIdx)) {
1398 auto Idx = CIdx->getZExtValue();
1399 const auto SplitIdx = SourceStrategy.splitPart(Idx);
1400 const auto ValueIdx =
1401 std::min(SplitIdx, (unsigned)SourceStrategy.getExpanded().size() - 1);
1402 Source = SourceStrategy.getValue(ValueIdx);
1403
1404 const auto EIdx = Idx -
1405 SourceStrategy.toSliceStart(
1406 std::min(SourceStrategy.extra(), SplitIdx));
1407 NewIdx = ConstantInt::get(I32Ty, EIdx);
1408 } else {
1409 assert(SourceStrategy.extra() == 0);
1410 Source = SourceStrategy.getValue(0);
1411 NewIdx = OriginalIdx;
1412 }
1413 assert(Source && NewIdx);
1414 Extracted = Builder.CreateExtractElement(Source, NewIdx);
1415 } else {
1416 /// Similar to InsertElementInst, chain ICmp + select to find the right
1417 /// index.
1418 Extracted = UndefValue::get(Extract->getType());
1419 for (unsigned Part = 0; Part < SourceStrategy.values(); ++Part) {
1420 const unsigned Start = SourceStrategy.toSliceStart(Part);
1421 const unsigned End =
1422 SourceStrategy.toSliceEnd(Part, SourceStrategy.fromElements());
1423 auto *Source = SourceStrategy.getValue(Part);
1424 for (unsigned PartIdx = 0; PartIdx + Start < End; ++PartIdx) {
1425 auto *NewIdx = ConstantInt::get(I32Ty, PartIdx);
1426 Value *ExtractedTemp = Builder.CreateExtractElement(Source, NewIdx);
1427
1428 Value *COriginalIdx =
1429 ConstantInt::get(OriginalIdx->getType(), PartIdx + Start);
1430
1431 Value *Cmp =
1432 Builder.CreateICmp(CmpInst::ICMP_EQ, COriginalIdx, OriginalIdx);
1433 Extracted = Builder.CreateSelect(Cmp, ExtractedTemp, Extracted);
1434 }
1435 }
1436 }
1437
1438 assert(Extracted);
1439 Extract->replaceAllUsesWith(Extracted);
1440 ToDelete.push_back(Extract);
1441 }
1442 void VectorCanonicalizationInstructionPass::fixCallInstruction(CallInst *Call) {
1443 auto *Called = Call->getCalledValue();
1444 auto *FTy = cast<FunctionType>(Called->getType()->getContainedType(0));
1445 auto &FStrategy = FPass.buildStrategy(FTy, DL);
1446 if (!FStrategy) {
1447 return;
1448 }
1449
1450 assert(!FStrategy.getRet());
1451
1452 SmallVector<Value *, 8> NewArgs;
1453 IRBuilder<> Builder(Call);
1454
1455 const auto &ArgStrategies = FStrategy.getArgs();
1456 assert(ArgStrategies.size() == Call->getNumArgOperands());
1457 for (unsigned I = 0; I < ArgStrategies.size(); ++I) {
1458 const auto &ArgStrategy = ArgStrategies[I];
1459 auto *Param = Call->getArgOperand(I);
1460 if (!ArgStrategy) {
1461 NewArgs.push_back(Param);
1462 continue;
1463 }
1464
1465 const auto &ParamStrategy = findStrategyFor(Param, Call);
1466 assert(ParamStrategy);
1467 for (Value *Expanded : ParamStrategy.getExpanded()) {
1468 NewArgs.push_back(Expanded);
1469 }
1470 }
1471
1472 auto *NewFTyPtr = FStrategy.newFunctionType()->getPointerTo();
1473 Value *CastedCalled = Builder.CreatePointerCast(Called, NewFTyPtr);
1474 CallInst *NewCall = Builder.CreateCall(CastedCalled, NewArgs);
1475
1476 auto NewAttrs =
1477 FStrategy.mapAttrs(Call->getAttributes(), Call->getContext(),
1478 Call->getParent()->getModule()->getDataLayout());
1479 NewCall->setAttributes(NewAttrs);
1480
1481 ToDelete.push_back(Call);
1482 }
1483 void VectorCanonicalizationInstructionPass::fixShuffleInstruction(
1484 ShuffleVectorInst *Shuffle) {
1485 SmallVector<std::tuple<Value *, Value *, unsigned>, 16> Values;
1486
1487 const auto Mask = Shuffle->getShuffleMask();
1488 const auto &LeftStrategy = findStrategyFor(Shuffle->getOperand(0), Shuffle);
1489 const auto &RightStrategy = findStrategyFor(Shuffle->getOperand(1), Shuffle);
1490
1491 if (!LeftStrategy && !RightStrategy) {
1492 return;
1493 }
1494
1495 getShuffleValues(LeftStrategy, RightStrategy, Mask, Values);
1496
1497 const unsigned Start = 0;
1498 const unsigned End = Shuffle->getType()->getVectorNumElements();
1499
1500 IRBuilder<> Builder(Shuffle);
1501
1502 Value *NewShuffle =
1503 shuffleRebuildHelper(Shuffle, Builder, Values, Start, End);
1504 Shuffle->replaceAllUsesWith(NewShuffle);
1505 ToDelete.push_back(Shuffle);
1506 }
1507 void VectorCanonicalizationInstructionPass::fixCastInstruction(CastInst *Cast) {
1508 if (!findStrategyFor(Cast->getOperand(0), Cast)) {
1509 return;
1510 }
1511
1512 // If we make it here, it means we have a vector size changing cast.
1513
1514 IRBuilder<> Builder(Cast);
1515
1516 const auto &SourceStrategy = findStrategyFor(Cast->getOperand(0), Cast);
1517 const auto Opcode = Cast->getOpcode();
1518 auto *ToVTy = cast<VectorType>(Cast->getType());
1519 auto *ToElementTy = ToVTy->getElementType();
1520 auto *I32Ty = IntegerType::get(Cast->getContext(), 32);
1521
1522 Value *Inserted = UndefValue::get(ToVTy);
1523 for (unsigned I = 0; I < Cast->getType()->getVectorNumElements(); ++I) {
1524 const auto SourcePart = SourceStrategy.splitPart(I);
1525 Value *Source = SourceStrategy.getValue(SourcePart);
1526 auto *ExtractIdx =
1527 ConstantInt::get(I32Ty, I - SourceStrategy.toSliceStart(SourcePart));
1528 Value *Extracted = Builder.CreateExtractElement(Source, ExtractIdx);
1529 Value *Casted = Builder.CreateCast(Opcode, Extracted, ToElementTy);
1530 Inserted = Builder.CreateInsertElement(Inserted, Casted,
1531 ConstantInt::get(I32Ty, I));
1532 }
1533
1534 Cast->replaceAllUsesWith(Inserted);
1535 ToDelete.push_back(Cast);
1536 }
1537
1538 bool VectorCanonicalizationInstructionPass::fixCmpInstruction(
1539 InstructionStrategy &Strategy, CmpInst *Cmp, IRBuilder<> &Builder) {
1540 const auto &Left = findStrategyFor(Cmp->getOperand(0), Cmp);
1541
1542 if (Left.toElements() != Strategy.toElements()) {
1543 // The operands were promoted but the cmp's type might be a technically
1544 // legal i1 vector.
1545 // Force the promotion here.
1546 Strategy.To =
1547 VectorType::get(Type::getInt1Ty(Cmp->getContext()), Left.toElements());
1548 } else if (!Left) {
1549 return false;
1550 }
1551
1552 const auto Opcode = Cmp->getOpcode();
1553 const auto Predicate = Cmp->getPredicate();
1554 const auto &Right = findStrategyFor(Cmp->getOperand(1), Cmp);
1555
1556 auto Callback = [Opcode, Predicate, &Left, &Right, Cmp, &Builder](
1557 const unsigned Part, const unsigned, const unsigned) {
1558 switch (Opcode) {
1559 default:
1560 Cmp->dump();
1561 llvm_unreachable("unhandled cmp instruction?");
1562 case Instruction::ICmp:
1563 return Builder.CreateICmp(Predicate, Left.getValue(Part),
1564 Right.getValue(Part));
1565 case Instruction::FCmp:
1566 return Builder.CreateFCmp(Predicate, Left.getValue(Part),
1567 Right.getValue(Part));
1568 };
1569 };
1570 Strategy.forEach(std::move(Callback));
1571
1572 return true;
1573 }
1574
1575 void VectorCanonicalizationInstructionPass::fixPhiNodes() {
1576 /// Now that we've gone over the whole function, fix up the phi nodes.
1577 for (const auto &Strategy : PhiNodes) {
1578 PHINode *Phi = cast<PHINode>(Strategy.getSource());
1579
1580 const auto &Expanded = Strategy.getExpanded();
1581
1582 const unsigned Count = Phi->getNumIncomingValues();
1583 for (unsigned I = 0; I < Count; ++I) {
1584 Value *Val = Phi->getIncomingValue(I);
1585 BasicBlock *BB = Phi->getIncomingBlock(I);
1586
1587 const auto &ValStrategy = findStrategyFor(Val, BB->getTerminator());
1588 assert(ValStrategy.values() == Strategy.values());
1589 for (unsigned J = 0; J < Expanded.size(); ++J) {
1590 PHINode *ExpandedPhi = cast<PHINode>(Expanded[J]);
1591 ExpandedPhi->addIncoming(ValStrategy.getValue(J), BB);
1592 }
1593 }
1594 }
1595
1596 PhiNodes.clear();
1597 }
1598
1599 void VectorCanonicalizationInstructionPass::getShuffleValues(
1600 const InstructionStrategy &LeftStrategy,
1601 const InstructionStrategy &RightStrategy, const SmallVectorImpl<int> &Mask,
1602 SmallVectorImpl<std::tuple<Value *, Value *, unsigned>> &Values) const {
1603 /// TODO keep the negative indices instead of rewriting them to a shuffle on
1604 /// an UndefValue.
1605 const auto FirstHalf = LeftStrategy.fromElements();
1606
1607 for (auto Idx : Mask) {
1608 if (Idx < 0) {
1609 /// Negative index indicating an undefined value.
1610 Value *Val = UndefValue::get(LeftStrategy.To);
1611 auto Pair = std::make_tuple(Val, UndefValue::get(LeftStrategy.From), 0);
1612 Values.push_back(Pair);
1613 } else if ((unsigned)Idx >= FirstHalf) {
1614 /// second half
1615 const auto RelIdx = Idx - FirstHalf;
1616 const auto Part = RightStrategy.splitPart(RelIdx);
1617 Value *Value = RightStrategy.getValue(Part);
1618 auto Pair = std::make_tuple(Value, RightStrategy.getSource(),
1619 RelIdx - RightStrategy.toSliceStart(Part));
1620 Values.push_back(Pair);
1621 } else {
1622 /// first half
1623 const auto Part = LeftStrategy.splitPart(Idx);
1624 Value *Value = LeftStrategy.getValue(Part);
1625 auto Pair = std::make_tuple(Value, LeftStrategy.getSource(),
1626 Idx - LeftStrategy.toSliceStart(Part));
1627 Values.push_back(Pair);
1628 }
1629 }
1630 }
1631 Value *VectorCanonicalizationInstructionPass::shuffleRebuildHelper(
1632 ShuffleVectorInst *Shuffle, IRBuilder<> &Builder,
1633 SmallVectorImpl<std::tuple<Value *, Value *, unsigned>> &Values,
1634 const unsigned Start, const unsigned End) {
1635
1636 bool Identity = true;
1637 /// Map identities straight through.
1638 Value *Prev = std::get<0>(Values[Start]);
1639 for (unsigned I = Start; Identity && I < std::min((size_t)End, Values.size());
1640 ++I) {
1641 Identity =
1642 Prev == std::get<0>(Values[I]) && std::get<2>(Values[I]) == I - Start;
1643 if (!Identity) {
1644 break;
1645 }
1646 }
1647 if (Identity) {
1648 return Prev;
1649 }
1650
1651 SmallVector<std::tuple<Value *, Value *>, 2> Operands;
1652
1653 auto IsNewOperand = [&Operands](Value *V) {
1654 for (auto &Op : Operands) {
1655 if (std::get<0>(Op) == V) {
1656 return false;
1657 }
1658 }
1659
1660 return true;
1661 };
1662 auto GetOperandOffset = [&Operands](Value *V) {
1663 unsigned I = 0;
1664 for (auto &Op : Operands) {
1665 if (std::get<0>(Op) == V) {
1666 break;
1667 }
1668 ++I;
1669 }
1670 assert(I < Operands.size());
1671
1672 return I * std::get<0>(Operands.front())->getType()->getVectorNumElements();
1673 };
1674
1675 SmallVector<int, 8> NewMask;
1676
1677 auto FillNewMask = [&NewMask, End, Start]() {
1678 assert(NewMask.size() != 0);
1679 for (unsigned J = NewMask.size(); J < End - Start; ++J) {
1680 NewMask.push_back(NewMask.back());
1681 }
1682 };
1683 for (unsigned I = Start; I < std::min((size_t)End, Values.size()); ++I) {
1684 const bool IsNew = IsNewOperand(std::get<0>(Values[I]));
1685 if (IsNew && Operands.size() < 2) {
1686 Operands.push_back(
1687 std::make_tuple(std::get<0>(Values[I]), std::get<1>(Values[I])));
1688 } else if (IsNew && Operands.size() == 2) {
1689 /// We have to chain this shuffle because this part uses more than
1690 /// two source parts.
1691 const auto Size = NewMask.size();
1692 FillNewMask();
1693
1694 Value *Shuffle = Builder.CreateShuffleVector(
1695 std::get<0>(Operands[0]), std::get<0>(Operands[1]), NewMask);
1696 NewMask.clear();
1697 for (unsigned J = 0; J < Size; ++J) {
1698 NewMask.push_back(J);
1699 }
1700
1701 Operands.clear();
1702 Operands.push_back(std::make_tuple(Shuffle, nullptr));
1703 Operands.push_back(
1704 std::make_tuple(std::get<0>(Values[I]), std::get<1>(Values[I])));
1705 }
1706
1707 assert(Operands.size() >= 1 && Operands.size() <= 2);
1708 const unsigned Offset = GetOperandOffset(std::get<0>(Values[I]));
1709 NewMask.push_back(std::get<2>(Values[I]) + Offset);
1710 }
1711
1712 FillNewMask();
1713
1714 if (Operands.size() == 1) {
1715 // Check for and bypass shuffles the function pass inserted for returns.
1716 // This can only happen when the return is expanded.
1717 // Not only does this make our generated IR cleaner, it also keeps the test
1718 // generator I built for this pass simple.
1719 const auto &OperandStrategy =
1720 findStrategyFor(std::get<1>(Operands.front()), Shuffle);
1721 bool ByPass = OperandStrategy.getValue(OperandStrategy.extra()) ==
1722 std::get<0>(Operands.front());
1723 const auto Rem = OperandStrategy.rem();
1724 for (unsigned I = 0; ByPass && I < NewMask.size(); ++I) {
1725 int ExpectedVal = 0;
1726 if (Rem != 0 && I > Rem - 1) {
1727 ExpectedVal = Rem - 1;
1728 } else {
1729 ExpectedVal = I;
1730 }
1731
1732 ByPass = ExpectedVal == NewMask[I];
1733 }
1734 if (ByPass) {
1735 Value *Front = std::get<0>(Operands.front());
1736 return Front;
1737 }
1738
1739 auto Push = std::make_tuple(
1740 UndefValue::get(std::get<0>(Operands[0])->getType()), nullptr);
1741 Operands.push_back(Push);
1742 }
1743
1744 Value *NewShuffle = Builder.CreateShuffleVector(
1745 std::get<0>(Operands[0]), std::get<0>(Operands[1]), NewMask);
1746 return NewShuffle;
1747 }
1748
1749 namespace {
1750 class PNaClVectorCanonicalization : public ModulePass {
1751 BitWidthMapper Cfg;
1752
1753 public:
1754 static char ID;
1755 PNaClVectorCanonicalization() : ModulePass(ID), Cfg() {
1756 initializePNaClVectorCanonicalizationPass(*PassRegistry::getPassRegistry());
1757 Cfg.NormWidths.push_back(128);
1758 Cfg.I1NumElements.push_back(2);
1759 Cfg.I1NumElements.push_back(4);
1760 Cfg.I1NumElements.push_back(8);
1761 Cfg.I1NumElements.push_back(16);
1762 }
1763
1764 bool runOnModule(Module &M);
1765 };
1766 char PNaClVectorCanonicalization::ID = 0;
1767 }
1768 INITIALIZE_PASS(PNaClVectorCanonicalization, "pnacl-vector-canonicalization",
1769 "Convert improper vector types into proper ones", false, false)
1770
1771 ModulePass *llvm::createPNaClVectorCanonicalizationPass() {
1772 return new PNaClVectorCanonicalization();
1773 }
1774
1775 bool PNaClVectorCanonicalization::runOnModule(Module &M) {
1776 VectorCanonicalizationFunctionPass FPass(Cfg);
1777 FPass.runOnModule(M);
1778
1779 bool Modified = FPass.modified();
1780
1781 for (auto FI = M.begin(); FI != M.end(); ++FI) {
1782 if (FI->size() == 0) {
1783 continue;
1784 }
1785
1786 VectorCanonicalizationInstructionPass IPass(&*FI, Cfg, FPass);
1787 IPass.runOnFunction(*FI);
1788
1789 Modified |= IPass.modified();
1790 }
1791
1792 return Modified;
1793 }
OLDNEW
« no previous file with comments | « lib/Transforms/NaCl/PNaClABISimplify.cpp ('k') | test/Transforms/NaCl/vector-canonicalization-binops.ll » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698