13dac3a9bSDimitry Andric //=----------------------- InterleavedAccessPass.cpp -----------------------==// 23dac3a9bSDimitry Andric // 33dac3a9bSDimitry Andric // The LLVM Compiler Infrastructure 43dac3a9bSDimitry Andric // 53dac3a9bSDimitry Andric // This file is distributed under the University of Illinois Open Source 63dac3a9bSDimitry Andric // License. See LICENSE.TXT for details. 73dac3a9bSDimitry Andric // 83dac3a9bSDimitry Andric //===----------------------------------------------------------------------===// 93dac3a9bSDimitry Andric // 103dac3a9bSDimitry Andric // This file implements the Interleaved Access pass, which identifies 113dac3a9bSDimitry Andric // interleaved memory accesses and transforms into target specific intrinsics. 123dac3a9bSDimitry Andric // 133dac3a9bSDimitry Andric // An interleaved load reads data from memory into several vectors, with 143dac3a9bSDimitry Andric // DE-interleaving the data on a factor. An interleaved store writes several 153dac3a9bSDimitry Andric // vectors to memory with RE-interleaving the data on a factor. 163dac3a9bSDimitry Andric // 173dac3a9bSDimitry Andric // As interleaved accesses are hard to be identified in CodeGen (mainly because 183dac3a9bSDimitry Andric // the VECTOR_SHUFFLE DAG node is quite different from the shufflevector IR), 193dac3a9bSDimitry Andric // we identify and transform them to intrinsics in this pass. So the intrinsics 203dac3a9bSDimitry Andric // can be easily matched into target specific instructions later in CodeGen. 213dac3a9bSDimitry Andric // 223dac3a9bSDimitry Andric // E.g. An interleaved load (Factor = 2): 233dac3a9bSDimitry Andric // %wide.vec = load <8 x i32>, <8 x i32>* %ptr 243dac3a9bSDimitry Andric // %v0 = shuffle <8 x i32> %wide.vec, <8 x i32> undef, <0, 2, 4, 6> 253dac3a9bSDimitry Andric // %v1 = shuffle <8 x i32> %wide.vec, <8 x i32> undef, <1, 3, 5, 7> 263dac3a9bSDimitry Andric // 273dac3a9bSDimitry Andric // It could be transformed into a ld2 intrinsic in AArch64 backend or a vld2 283dac3a9bSDimitry Andric // intrinsic in ARM backend. 293dac3a9bSDimitry Andric // 303dac3a9bSDimitry Andric // E.g. An interleaved store (Factor = 3): 313dac3a9bSDimitry Andric // %i.vec = shuffle <8 x i32> %v0, <8 x i32> %v1, 323dac3a9bSDimitry Andric // <0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11> 333dac3a9bSDimitry Andric // store <12 x i32> %i.vec, <12 x i32>* %ptr 343dac3a9bSDimitry Andric // 353dac3a9bSDimitry Andric // It could be transformed into a st3 intrinsic in AArch64 backend or a vst3 363dac3a9bSDimitry Andric // intrinsic in ARM backend. 373dac3a9bSDimitry Andric // 383dac3a9bSDimitry Andric //===----------------------------------------------------------------------===// 393dac3a9bSDimitry Andric 403dac3a9bSDimitry Andric #include "llvm/CodeGen/Passes.h" 413dac3a9bSDimitry Andric #include "llvm/IR/InstIterator.h" 423dac3a9bSDimitry Andric #include "llvm/Support/Debug.h" 433dac3a9bSDimitry Andric #include "llvm/Support/MathExtras.h" 443dac3a9bSDimitry Andric #include "llvm/Support/raw_ostream.h" 453dac3a9bSDimitry Andric #include "llvm/Target/TargetLowering.h" 463dac3a9bSDimitry Andric #include "llvm/Target/TargetSubtargetInfo.h" 473dac3a9bSDimitry Andric 483dac3a9bSDimitry Andric using namespace llvm; 493dac3a9bSDimitry Andric 503dac3a9bSDimitry Andric #define DEBUG_TYPE "interleaved-access" 513dac3a9bSDimitry Andric 523dac3a9bSDimitry Andric static cl::opt<bool> LowerInterleavedAccesses( 533dac3a9bSDimitry Andric "lower-interleaved-accesses", 543dac3a9bSDimitry Andric cl::desc("Enable lowering interleaved accesses to intrinsics"), 553dac3a9bSDimitry Andric cl::init(false), cl::Hidden); 563dac3a9bSDimitry Andric 573dac3a9bSDimitry Andric static unsigned MaxFactor; // The maximum supported interleave factor. 583dac3a9bSDimitry Andric 593dac3a9bSDimitry Andric namespace llvm { 603dac3a9bSDimitry Andric static void initializeInterleavedAccessPass(PassRegistry &); 613dac3a9bSDimitry Andric } 623dac3a9bSDimitry Andric 633dac3a9bSDimitry Andric namespace { 643dac3a9bSDimitry Andric 653dac3a9bSDimitry Andric class InterleavedAccess : public FunctionPass { 663dac3a9bSDimitry Andric 673dac3a9bSDimitry Andric public: 683dac3a9bSDimitry Andric static char ID; 693dac3a9bSDimitry Andric InterleavedAccess(const TargetMachine *TM = nullptr) 703dac3a9bSDimitry Andric : FunctionPass(ID), TM(TM), TLI(nullptr) { 713dac3a9bSDimitry Andric initializeInterleavedAccessPass(*PassRegistry::getPassRegistry()); 723dac3a9bSDimitry Andric } 733dac3a9bSDimitry Andric 743dac3a9bSDimitry Andric const char *getPassName() const override { return "Interleaved Access Pass"; } 753dac3a9bSDimitry Andric 763dac3a9bSDimitry Andric bool runOnFunction(Function &F) override; 773dac3a9bSDimitry Andric 783dac3a9bSDimitry Andric private: 793dac3a9bSDimitry Andric const TargetMachine *TM; 803dac3a9bSDimitry Andric const TargetLowering *TLI; 813dac3a9bSDimitry Andric 823dac3a9bSDimitry Andric /// \brief Transform an interleaved load into target specific intrinsics. 833dac3a9bSDimitry Andric bool lowerInterleavedLoad(LoadInst *LI, 843dac3a9bSDimitry Andric SmallVector<Instruction *, 32> &DeadInsts); 853dac3a9bSDimitry Andric 863dac3a9bSDimitry Andric /// \brief Transform an interleaved store into target specific intrinsics. 873dac3a9bSDimitry Andric bool lowerInterleavedStore(StoreInst *SI, 883dac3a9bSDimitry Andric SmallVector<Instruction *, 32> &DeadInsts); 893dac3a9bSDimitry Andric }; 903dac3a9bSDimitry Andric } // end anonymous namespace. 913dac3a9bSDimitry Andric 923dac3a9bSDimitry Andric char InterleavedAccess::ID = 0; 933dac3a9bSDimitry Andric INITIALIZE_TM_PASS(InterleavedAccess, "interleaved-access", 943dac3a9bSDimitry Andric "Lower interleaved memory accesses to target specific intrinsics", 953dac3a9bSDimitry Andric false, false) 963dac3a9bSDimitry Andric 973dac3a9bSDimitry Andric FunctionPass *llvm::createInterleavedAccessPass(const TargetMachine *TM) { 983dac3a9bSDimitry Andric return new InterleavedAccess(TM); 993dac3a9bSDimitry Andric } 1003dac3a9bSDimitry Andric 1013dac3a9bSDimitry Andric /// \brief Check if the mask is a DE-interleave mask of the given factor 1023dac3a9bSDimitry Andric /// \p Factor like: 1033dac3a9bSDimitry Andric /// <Index, Index+Factor, ..., Index+(NumElts-1)*Factor> 1043dac3a9bSDimitry Andric static bool isDeInterleaveMaskOfFactor(ArrayRef<int> Mask, unsigned Factor, 1053dac3a9bSDimitry Andric unsigned &Index) { 1063dac3a9bSDimitry Andric // Check all potential start indices from 0 to (Factor - 1). 1073dac3a9bSDimitry Andric for (Index = 0; Index < Factor; Index++) { 1083dac3a9bSDimitry Andric unsigned i = 0; 1093dac3a9bSDimitry Andric 1103dac3a9bSDimitry Andric // Check that elements are in ascending order by Factor. Ignore undef 1113dac3a9bSDimitry Andric // elements. 1123dac3a9bSDimitry Andric for (; i < Mask.size(); i++) 1133dac3a9bSDimitry Andric if (Mask[i] >= 0 && static_cast<unsigned>(Mask[i]) != Index + i * Factor) 1143dac3a9bSDimitry Andric break; 1153dac3a9bSDimitry Andric 1163dac3a9bSDimitry Andric if (i == Mask.size()) 1173dac3a9bSDimitry Andric return true; 1183dac3a9bSDimitry Andric } 1193dac3a9bSDimitry Andric 1203dac3a9bSDimitry Andric return false; 1213dac3a9bSDimitry Andric } 1223dac3a9bSDimitry Andric 1233dac3a9bSDimitry Andric /// \brief Check if the mask is a DE-interleave mask for an interleaved load. 1243dac3a9bSDimitry Andric /// 1253dac3a9bSDimitry Andric /// E.g. DE-interleave masks (Factor = 2) could be: 1263dac3a9bSDimitry Andric /// <0, 2, 4, 6> (mask of index 0 to extract even elements) 1273dac3a9bSDimitry Andric /// <1, 3, 5, 7> (mask of index 1 to extract odd elements) 1283dac3a9bSDimitry Andric static bool isDeInterleaveMask(ArrayRef<int> Mask, unsigned &Factor, 1293dac3a9bSDimitry Andric unsigned &Index) { 1303dac3a9bSDimitry Andric if (Mask.size() < 2) 1313dac3a9bSDimitry Andric return false; 1323dac3a9bSDimitry Andric 1333dac3a9bSDimitry Andric // Check potential Factors. 1343dac3a9bSDimitry Andric for (Factor = 2; Factor <= MaxFactor; Factor++) 1353dac3a9bSDimitry Andric if (isDeInterleaveMaskOfFactor(Mask, Factor, Index)) 1363dac3a9bSDimitry Andric return true; 1373dac3a9bSDimitry Andric 1383dac3a9bSDimitry Andric return false; 1393dac3a9bSDimitry Andric } 1403dac3a9bSDimitry Andric 1413dac3a9bSDimitry Andric /// \brief Check if the mask is RE-interleave mask for an interleaved store. 1423dac3a9bSDimitry Andric /// 1433dac3a9bSDimitry Andric /// I.e. <0, NumSubElts, ... , NumSubElts*(Factor - 1), 1, NumSubElts + 1, ...> 1443dac3a9bSDimitry Andric /// 1453dac3a9bSDimitry Andric /// E.g. The RE-interleave mask (Factor = 2) could be: 1463dac3a9bSDimitry Andric /// <0, 4, 1, 5, 2, 6, 3, 7> 1473dac3a9bSDimitry Andric static bool isReInterleaveMask(ArrayRef<int> Mask, unsigned &Factor) { 1483dac3a9bSDimitry Andric unsigned NumElts = Mask.size(); 1493dac3a9bSDimitry Andric if (NumElts < 4) 1503dac3a9bSDimitry Andric return false; 1513dac3a9bSDimitry Andric 1523dac3a9bSDimitry Andric // Check potential Factors. 1533dac3a9bSDimitry Andric for (Factor = 2; Factor <= MaxFactor; Factor++) { 1543dac3a9bSDimitry Andric if (NumElts % Factor) 1553dac3a9bSDimitry Andric continue; 1563dac3a9bSDimitry Andric 1573dac3a9bSDimitry Andric unsigned NumSubElts = NumElts / Factor; 1583dac3a9bSDimitry Andric if (!isPowerOf2_32(NumSubElts)) 1593dac3a9bSDimitry Andric continue; 1603dac3a9bSDimitry Andric 1613dac3a9bSDimitry Andric // Check whether each element matchs the RE-interleaved rule. Ignore undef 1623dac3a9bSDimitry Andric // elements. 1633dac3a9bSDimitry Andric unsigned i = 0; 1643dac3a9bSDimitry Andric for (; i < NumElts; i++) 1653dac3a9bSDimitry Andric if (Mask[i] >= 0 && 1663dac3a9bSDimitry Andric static_cast<unsigned>(Mask[i]) != 1673dac3a9bSDimitry Andric (i % Factor) * NumSubElts + i / Factor) 1683dac3a9bSDimitry Andric break; 1693dac3a9bSDimitry Andric 1703dac3a9bSDimitry Andric // Find a RE-interleaved mask of current factor. 1713dac3a9bSDimitry Andric if (i == NumElts) 1723dac3a9bSDimitry Andric return true; 1733dac3a9bSDimitry Andric } 1743dac3a9bSDimitry Andric 1753dac3a9bSDimitry Andric return false; 1763dac3a9bSDimitry Andric } 1773dac3a9bSDimitry Andric 1783dac3a9bSDimitry Andric bool InterleavedAccess::lowerInterleavedLoad( 1793dac3a9bSDimitry Andric LoadInst *LI, SmallVector<Instruction *, 32> &DeadInsts) { 1803dac3a9bSDimitry Andric if (!LI->isSimple()) 1813dac3a9bSDimitry Andric return false; 1823dac3a9bSDimitry Andric 1833dac3a9bSDimitry Andric SmallVector<ShuffleVectorInst *, 4> Shuffles; 1843dac3a9bSDimitry Andric 1853dac3a9bSDimitry Andric // Check if all users of this load are shufflevectors. 1863dac3a9bSDimitry Andric for (auto UI = LI->user_begin(), E = LI->user_end(); UI != E; UI++) { 1873dac3a9bSDimitry Andric ShuffleVectorInst *SVI = dyn_cast<ShuffleVectorInst>(*UI); 1883dac3a9bSDimitry Andric if (!SVI || !isa<UndefValue>(SVI->getOperand(1))) 1893dac3a9bSDimitry Andric return false; 1903dac3a9bSDimitry Andric 1913dac3a9bSDimitry Andric Shuffles.push_back(SVI); 1923dac3a9bSDimitry Andric } 1933dac3a9bSDimitry Andric 1943dac3a9bSDimitry Andric if (Shuffles.empty()) 1953dac3a9bSDimitry Andric return false; 1963dac3a9bSDimitry Andric 1973dac3a9bSDimitry Andric unsigned Factor, Index; 1983dac3a9bSDimitry Andric 1993dac3a9bSDimitry Andric // Check if the first shufflevector is DE-interleave shuffle. 2003dac3a9bSDimitry Andric if (!isDeInterleaveMask(Shuffles[0]->getShuffleMask(), Factor, Index)) 2013dac3a9bSDimitry Andric return false; 2023dac3a9bSDimitry Andric 2033dac3a9bSDimitry Andric // Holds the corresponding index for each DE-interleave shuffle. 2043dac3a9bSDimitry Andric SmallVector<unsigned, 4> Indices; 2053dac3a9bSDimitry Andric Indices.push_back(Index); 2063dac3a9bSDimitry Andric 2073dac3a9bSDimitry Andric Type *VecTy = Shuffles[0]->getType(); 2083dac3a9bSDimitry Andric 2093dac3a9bSDimitry Andric // Check if other shufflevectors are also DE-interleaved of the same type 2103dac3a9bSDimitry Andric // and factor as the first shufflevector. 2113dac3a9bSDimitry Andric for (unsigned i = 1; i < Shuffles.size(); i++) { 2123dac3a9bSDimitry Andric if (Shuffles[i]->getType() != VecTy) 2133dac3a9bSDimitry Andric return false; 2143dac3a9bSDimitry Andric 2153dac3a9bSDimitry Andric if (!isDeInterleaveMaskOfFactor(Shuffles[i]->getShuffleMask(), Factor, 2163dac3a9bSDimitry Andric Index)) 2173dac3a9bSDimitry Andric return false; 2183dac3a9bSDimitry Andric 2193dac3a9bSDimitry Andric Indices.push_back(Index); 2203dac3a9bSDimitry Andric } 2213dac3a9bSDimitry Andric 2223dac3a9bSDimitry Andric DEBUG(dbgs() << "IA: Found an interleaved load: " << *LI << "\n"); 2233dac3a9bSDimitry Andric 2243dac3a9bSDimitry Andric // Try to create target specific intrinsics to replace the load and shuffles. 2253dac3a9bSDimitry Andric if (!TLI->lowerInterleavedLoad(LI, Shuffles, Indices, Factor)) 2263dac3a9bSDimitry Andric return false; 2273dac3a9bSDimitry Andric 2283dac3a9bSDimitry Andric for (auto SVI : Shuffles) 2293dac3a9bSDimitry Andric DeadInsts.push_back(SVI); 2303dac3a9bSDimitry Andric 2313dac3a9bSDimitry Andric DeadInsts.push_back(LI); 2323dac3a9bSDimitry Andric return true; 2333dac3a9bSDimitry Andric } 2343dac3a9bSDimitry Andric 2353dac3a9bSDimitry Andric bool InterleavedAccess::lowerInterleavedStore( 2363dac3a9bSDimitry Andric StoreInst *SI, SmallVector<Instruction *, 32> &DeadInsts) { 2373dac3a9bSDimitry Andric if (!SI->isSimple()) 2383dac3a9bSDimitry Andric return false; 2393dac3a9bSDimitry Andric 2403dac3a9bSDimitry Andric ShuffleVectorInst *SVI = dyn_cast<ShuffleVectorInst>(SI->getValueOperand()); 2413dac3a9bSDimitry Andric if (!SVI || !SVI->hasOneUse()) 2423dac3a9bSDimitry Andric return false; 2433dac3a9bSDimitry Andric 2443dac3a9bSDimitry Andric // Check if the shufflevector is RE-interleave shuffle. 2453dac3a9bSDimitry Andric unsigned Factor; 2463dac3a9bSDimitry Andric if (!isReInterleaveMask(SVI->getShuffleMask(), Factor)) 2473dac3a9bSDimitry Andric return false; 2483dac3a9bSDimitry Andric 2493dac3a9bSDimitry Andric DEBUG(dbgs() << "IA: Found an interleaved store: " << *SI << "\n"); 2503dac3a9bSDimitry Andric 2513dac3a9bSDimitry Andric // Try to create target specific intrinsics to replace the store and shuffle. 2523dac3a9bSDimitry Andric if (!TLI->lowerInterleavedStore(SI, SVI, Factor)) 2533dac3a9bSDimitry Andric return false; 2543dac3a9bSDimitry Andric 2553dac3a9bSDimitry Andric // Already have a new target specific interleaved store. Erase the old store. 2563dac3a9bSDimitry Andric DeadInsts.push_back(SI); 2573dac3a9bSDimitry Andric DeadInsts.push_back(SVI); 2583dac3a9bSDimitry Andric return true; 2593dac3a9bSDimitry Andric } 2603dac3a9bSDimitry Andric 2613dac3a9bSDimitry Andric bool InterleavedAccess::runOnFunction(Function &F) { 2623dac3a9bSDimitry Andric if (!TM || !LowerInterleavedAccesses) 2633dac3a9bSDimitry Andric return false; 2643dac3a9bSDimitry Andric 2653dac3a9bSDimitry Andric DEBUG(dbgs() << "*** " << getPassName() << ": " << F.getName() << "\n"); 2663dac3a9bSDimitry Andric 2673dac3a9bSDimitry Andric TLI = TM->getSubtargetImpl(F)->getTargetLowering(); 2683dac3a9bSDimitry Andric MaxFactor = TLI->getMaxSupportedInterleaveFactor(); 2693dac3a9bSDimitry Andric 2703dac3a9bSDimitry Andric // Holds dead instructions that will be erased later. 2713dac3a9bSDimitry Andric SmallVector<Instruction *, 32> DeadInsts; 2723dac3a9bSDimitry Andric bool Changed = false; 2733dac3a9bSDimitry Andric 2743dac3a9bSDimitry Andric for (auto &I : inst_range(F)) { 2753dac3a9bSDimitry Andric if (LoadInst *LI = dyn_cast<LoadInst>(&I)) 2763dac3a9bSDimitry Andric Changed |= lowerInterleavedLoad(LI, DeadInsts); 2773dac3a9bSDimitry Andric 2783dac3a9bSDimitry Andric if (StoreInst *SI = dyn_cast<StoreInst>(&I)) 2793dac3a9bSDimitry Andric Changed |= lowerInterleavedStore(SI, DeadInsts); 2803dac3a9bSDimitry Andric } 2813dac3a9bSDimitry Andric 2823dac3a9bSDimitry Andric for (auto I : DeadInsts) 2833dac3a9bSDimitry Andric I->eraseFromParent(); 2843dac3a9bSDimitry Andric 2853dac3a9bSDimitry Andric return Changed; 2863dac3a9bSDimitry Andric } 287