OLD | NEW |
(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 } |
OLD | NEW |