17b6f760fSDavid Green //===- MVELaneInterleaving.cpp - Inverleave for MVE instructions ----------===// 27b6f760fSDavid Green // 37b6f760fSDavid Green // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 47b6f760fSDavid Green // See https://llvm.org/LICENSE.txt for license information. 57b6f760fSDavid Green // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 67b6f760fSDavid Green // 77b6f760fSDavid Green //===----------------------------------------------------------------------===// 87b6f760fSDavid Green // 97b6f760fSDavid Green // This pass interleaves around sext/zext/trunc instructions. MVE does not have 107b6f760fSDavid Green // a single sext/zext or trunc instruction that takes the bottom half of a 117b6f760fSDavid Green // vector and extends to a full width, like NEON has with MOVL. Instead it is 127b6f760fSDavid Green // expected that this happens through top/bottom instructions. So the MVE 137b6f760fSDavid Green // equivalent VMOVLT/B instructions take either the even or odd elements of the 147b6f760fSDavid Green // input and extend them to the larger type, producing a vector with half the 157b6f760fSDavid Green // number of elements each of double the bitwidth. As there is no simple 167b6f760fSDavid Green // instruction, we often have to turn sext/zext/trunc into a series of lane 177b6f760fSDavid Green // moves (or stack loads/stores, which we do not do yet). 187b6f760fSDavid Green // 197b6f760fSDavid Green // This pass takes vector code that starts at truncs, looks for interconnected 207b6f760fSDavid Green // blobs of operations that end with sext/zext (or constants/splats) of the 217b6f760fSDavid Green // form: 227b6f760fSDavid Green // %sa = sext v8i16 %a to v8i32 237b6f760fSDavid Green // %sb = sext v8i16 %b to v8i32 247b6f760fSDavid Green // %add = add v8i32 %sa, %sb 257b6f760fSDavid Green // %r = trunc %add to v8i16 267b6f760fSDavid Green // And adds shuffles to allow the use of VMOVL/VMOVN instrctions: 277b6f760fSDavid Green // %sha = shuffle v8i16 %a, undef, <0, 2, 4, 6, 1, 3, 5, 7> 287b6f760fSDavid Green // %sa = sext v8i16 %sha to v8i32 297b6f760fSDavid Green // %shb = shuffle v8i16 %b, undef, <0, 2, 4, 6, 1, 3, 5, 7> 307b6f760fSDavid Green // %sb = sext v8i16 %shb to v8i32 317b6f760fSDavid Green // %add = add v8i32 %sa, %sb 327b6f760fSDavid Green // %r = trunc %add to v8i16 337b6f760fSDavid Green // %shr = shuffle v8i16 %r, undef, <0, 4, 1, 5, 2, 6, 3, 7> 347b6f760fSDavid Green // Which can then be split and lowered to MVE instructions efficiently: 357b6f760fSDavid Green // %sa_b = VMOVLB.s16 %a 367b6f760fSDavid Green // %sa_t = VMOVLT.s16 %a 377b6f760fSDavid Green // %sb_b = VMOVLB.s16 %b 387b6f760fSDavid Green // %sb_t = VMOVLT.s16 %b 397b6f760fSDavid Green // %add_b = VADD.i32 %sa_b, %sb_b 407b6f760fSDavid Green // %add_t = VADD.i32 %sa_t, %sb_t 417b6f760fSDavid Green // %r = VMOVNT.i16 %add_b, %add_t 427b6f760fSDavid Green // 437b6f760fSDavid Green //===----------------------------------------------------------------------===// 447b6f760fSDavid Green 457b6f760fSDavid Green #include "ARM.h" 467b6f760fSDavid Green #include "ARMBaseInstrInfo.h" 477b6f760fSDavid Green #include "ARMSubtarget.h" 487b6f760fSDavid Green #include "llvm/Analysis/TargetTransformInfo.h" 497b6f760fSDavid Green #include "llvm/CodeGen/TargetLowering.h" 507b6f760fSDavid Green #include "llvm/CodeGen/TargetPassConfig.h" 517b6f760fSDavid Green #include "llvm/CodeGen/TargetSubtargetInfo.h" 527b6f760fSDavid Green #include "llvm/IR/BasicBlock.h" 537b6f760fSDavid Green #include "llvm/IR/Constant.h" 547b6f760fSDavid Green #include "llvm/IR/Constants.h" 557b6f760fSDavid Green #include "llvm/IR/DerivedTypes.h" 567b6f760fSDavid Green #include "llvm/IR/Function.h" 577b6f760fSDavid Green #include "llvm/IR/IRBuilder.h" 587b6f760fSDavid Green #include "llvm/IR/InstIterator.h" 597b6f760fSDavid Green #include "llvm/IR/InstrTypes.h" 607b6f760fSDavid Green #include "llvm/IR/Instruction.h" 617b6f760fSDavid Green #include "llvm/IR/Instructions.h" 627b6f760fSDavid Green #include "llvm/IR/IntrinsicInst.h" 637b6f760fSDavid Green #include "llvm/IR/Intrinsics.h" 647b6f760fSDavid Green #include "llvm/IR/IntrinsicsARM.h" 657b6f760fSDavid Green #include "llvm/IR/PatternMatch.h" 667b6f760fSDavid Green #include "llvm/IR/Type.h" 677b6f760fSDavid Green #include "llvm/IR/Value.h" 687b6f760fSDavid Green #include "llvm/InitializePasses.h" 697b6f760fSDavid Green #include "llvm/Pass.h" 707b6f760fSDavid Green #include "llvm/Support/Casting.h" 717b6f760fSDavid Green #include <algorithm> 727b6f760fSDavid Green #include <cassert> 737b6f760fSDavid Green 747b6f760fSDavid Green using namespace llvm; 757b6f760fSDavid Green 767b6f760fSDavid Green #define DEBUG_TYPE "mve-laneinterleave" 777b6f760fSDavid Green 787b6f760fSDavid Green cl::opt<bool> EnableInterleave( 797b6f760fSDavid Green "enable-mve-interleave", cl::Hidden, cl::init(true), 807b6f760fSDavid Green cl::desc("Enable interleave MVE vector operation lowering")); 817b6f760fSDavid Green 827b6f760fSDavid Green namespace { 837b6f760fSDavid Green 847b6f760fSDavid Green class MVELaneInterleaving : public FunctionPass { 857b6f760fSDavid Green public: 867b6f760fSDavid Green static char ID; // Pass identification, replacement for typeid 877b6f760fSDavid Green 887b6f760fSDavid Green explicit MVELaneInterleaving() : FunctionPass(ID) { 897b6f760fSDavid Green initializeMVELaneInterleavingPass(*PassRegistry::getPassRegistry()); 907b6f760fSDavid Green } 917b6f760fSDavid Green 927b6f760fSDavid Green bool runOnFunction(Function &F) override; 937b6f760fSDavid Green 947b6f760fSDavid Green StringRef getPassName() const override { return "MVE lane interleaving"; } 957b6f760fSDavid Green 967b6f760fSDavid Green void getAnalysisUsage(AnalysisUsage &AU) const override { 977b6f760fSDavid Green AU.setPreservesCFG(); 987b6f760fSDavid Green AU.addRequired<TargetPassConfig>(); 997b6f760fSDavid Green FunctionPass::getAnalysisUsage(AU); 1007b6f760fSDavid Green } 1017b6f760fSDavid Green }; 1027b6f760fSDavid Green 1037b6f760fSDavid Green } // end anonymous namespace 1047b6f760fSDavid Green 1057b6f760fSDavid Green char MVELaneInterleaving::ID = 0; 1067b6f760fSDavid Green 1077b6f760fSDavid Green INITIALIZE_PASS(MVELaneInterleaving, DEBUG_TYPE, "MVE lane interleaving", false, 1087b6f760fSDavid Green false) 1097b6f760fSDavid Green 1107b6f760fSDavid Green Pass *llvm::createMVELaneInterleavingPass() { 1117b6f760fSDavid Green return new MVELaneInterleaving(); 1127b6f760fSDavid Green } 1137b6f760fSDavid Green 1147b6f760fSDavid Green static bool isProfitableToInterleave(SmallSetVector<Instruction *, 4> &Exts, 1157b6f760fSDavid Green SmallSetVector<Instruction *, 4> &Truncs) { 1167b6f760fSDavid Green // This is not always beneficial to transform. Exts can be incorporated into 1177b6f760fSDavid Green // loads, Truncs can be folded into stores. 1187b6f760fSDavid Green // Truncs are usually the same number of instructions, 1197b6f760fSDavid Green // VSTRH.32(A);VSTRH.32(B) vs VSTRH.16(VMOVNT A, B) with interleaving 1207b6f760fSDavid Green // Exts are unfortunately more instructions in the general case: 1217b6f760fSDavid Green // A=VLDRH.32; B=VLDRH.32; 1227b6f760fSDavid Green // vs with interleaving: 1237b6f760fSDavid Green // T=VLDRH.16; A=VMOVNB T; B=VMOVNT T 1247b6f760fSDavid Green // But those VMOVL may be folded into a VMULL. 1257b6f760fSDavid Green 1266c0a1ed3SDavid Green // But expensive extends/truncs are always good to remove. FPExts always 1276c0a1ed3SDavid Green // involve extra VCVT's so are always considered to be beneficial to convert. 1286c0a1ed3SDavid Green for (auto *E : Exts) { 1296c0a1ed3SDavid Green if (isa<FPExtInst>(E) || !isa<LoadInst>(E->getOperand(0))) { 1307b6f760fSDavid Green LLVM_DEBUG(dbgs() << "Beneficial due to " << *E << "\n"); 1317b6f760fSDavid Green return true; 1327b6f760fSDavid Green } 1336c0a1ed3SDavid Green } 1346c0a1ed3SDavid Green for (auto *T : Truncs) { 1357b6f760fSDavid Green if (T->hasOneUse() && !isa<StoreInst>(*T->user_begin())) { 1367b6f760fSDavid Green LLVM_DEBUG(dbgs() << "Beneficial due to " << *T << "\n"); 1377b6f760fSDavid Green return true; 1387b6f760fSDavid Green } 1396c0a1ed3SDavid Green } 1407b6f760fSDavid Green 1417b6f760fSDavid Green // Otherwise, we know we have a load(ext), see if any of the Extends are a 1427b6f760fSDavid Green // vmull. This is a simple heuristic and certainly not perfect. 1437b6f760fSDavid Green for (auto *E : Exts) { 1447b6f760fSDavid Green if (!E->hasOneUse() || 1457b6f760fSDavid Green cast<Instruction>(*E->user_begin())->getOpcode() != Instruction::Mul) { 1467b6f760fSDavid Green LLVM_DEBUG(dbgs() << "Not beneficial due to " << *E << "\n"); 1477b6f760fSDavid Green return false; 1487b6f760fSDavid Green } 1497b6f760fSDavid Green } 1507b6f760fSDavid Green return true; 1517b6f760fSDavid Green } 1527b6f760fSDavid Green 1537b6f760fSDavid Green static bool tryInterleave(Instruction *Start, 1547b6f760fSDavid Green SmallPtrSetImpl<Instruction *> &Visited) { 1557b6f760fSDavid Green LLVM_DEBUG(dbgs() << "tryInterleave from " << *Start << "\n"); 1567b6f760fSDavid Green auto *VT = cast<FixedVectorType>(Start->getType()); 1577b6f760fSDavid Green 1587b6f760fSDavid Green if (!isa<Instruction>(Start->getOperand(0))) 1597b6f760fSDavid Green return false; 1607b6f760fSDavid Green 1617b6f760fSDavid Green // Look for connected operations starting from Ext's, terminating at Truncs. 1627b6f760fSDavid Green std::vector<Instruction *> Worklist; 1637b6f760fSDavid Green Worklist.push_back(Start); 1647b6f760fSDavid Green Worklist.push_back(cast<Instruction>(Start->getOperand(0))); 1657b6f760fSDavid Green 1667b6f760fSDavid Green SmallSetVector<Instruction *, 4> Truncs; 1677b6f760fSDavid Green SmallSetVector<Instruction *, 4> Exts; 1683a68c6d2SDavid Green SmallSetVector<Use *, 4> OtherLeafs; 1697b6f760fSDavid Green SmallSetVector<Instruction *, 4> Ops; 1707b6f760fSDavid Green 1717b6f760fSDavid Green while (!Worklist.empty()) { 1727b6f760fSDavid Green Instruction *I = Worklist.back(); 1737b6f760fSDavid Green Worklist.pop_back(); 1747b6f760fSDavid Green 1757b6f760fSDavid Green switch (I->getOpcode()) { 1767b6f760fSDavid Green // Truncs 1777b6f760fSDavid Green case Instruction::Trunc: 1786c0a1ed3SDavid Green case Instruction::FPTrunc: 1797b6f760fSDavid Green if (Truncs.count(I)) 1807b6f760fSDavid Green continue; 1817b6f760fSDavid Green Truncs.insert(I); 1827b6f760fSDavid Green Visited.insert(I); 1837b6f760fSDavid Green break; 1847b6f760fSDavid Green 1857b6f760fSDavid Green // Extend leafs 1867b6f760fSDavid Green case Instruction::SExt: 1877b6f760fSDavid Green case Instruction::ZExt: 1886c0a1ed3SDavid Green case Instruction::FPExt: 1897b6f760fSDavid Green if (Exts.count(I)) 1907b6f760fSDavid Green continue; 1917b6f760fSDavid Green for (auto *Use : I->users()) 1927b6f760fSDavid Green Worklist.push_back(cast<Instruction>(Use)); 1937b6f760fSDavid Green Exts.insert(I); 1947b6f760fSDavid Green break; 1957b6f760fSDavid Green 196*dd31b2c6SDavid Green case Instruction::Call: { 197*dd31b2c6SDavid Green IntrinsicInst *II = dyn_cast<IntrinsicInst>(I); 198*dd31b2c6SDavid Green if (!II) 199*dd31b2c6SDavid Green return false; 200*dd31b2c6SDavid Green 201*dd31b2c6SDavid Green switch (II->getIntrinsicID()) { 202*dd31b2c6SDavid Green case Intrinsic::abs: 203*dd31b2c6SDavid Green case Intrinsic::smin: 204*dd31b2c6SDavid Green case Intrinsic::smax: 205*dd31b2c6SDavid Green case Intrinsic::umin: 206*dd31b2c6SDavid Green case Intrinsic::umax: 207*dd31b2c6SDavid Green case Intrinsic::sadd_sat: 208*dd31b2c6SDavid Green case Intrinsic::ssub_sat: 209*dd31b2c6SDavid Green case Intrinsic::uadd_sat: 210*dd31b2c6SDavid Green case Intrinsic::usub_sat: 211*dd31b2c6SDavid Green case Intrinsic::minnum: 212*dd31b2c6SDavid Green case Intrinsic::maxnum: 213*dd31b2c6SDavid Green case Intrinsic::fabs: 214*dd31b2c6SDavid Green case Intrinsic::fma: 215*dd31b2c6SDavid Green case Intrinsic::ceil: 216*dd31b2c6SDavid Green case Intrinsic::floor: 217*dd31b2c6SDavid Green case Intrinsic::rint: 218*dd31b2c6SDavid Green case Intrinsic::round: 219*dd31b2c6SDavid Green case Intrinsic::trunc: 220*dd31b2c6SDavid Green break; 221*dd31b2c6SDavid Green default: 222*dd31b2c6SDavid Green return false; 223*dd31b2c6SDavid Green } 224*dd31b2c6SDavid Green LLVM_FALLTHROUGH; // Fall through to treating these like an operator below. 225*dd31b2c6SDavid Green } 2267b6f760fSDavid Green // Binary/tertiary ops 2277b6f760fSDavid Green case Instruction::Add: 2287b6f760fSDavid Green case Instruction::Sub: 2297b6f760fSDavid Green case Instruction::Mul: 2307b6f760fSDavid Green case Instruction::AShr: 2317b6f760fSDavid Green case Instruction::LShr: 2327b6f760fSDavid Green case Instruction::Shl: 2337b6f760fSDavid Green case Instruction::ICmp: 2346c0a1ed3SDavid Green case Instruction::FCmp: 2356c0a1ed3SDavid Green case Instruction::FAdd: 2366c0a1ed3SDavid Green case Instruction::FMul: 2377b6f760fSDavid Green case Instruction::Select: 2387b6f760fSDavid Green if (Ops.count(I)) 2397b6f760fSDavid Green continue; 2407b6f760fSDavid Green Ops.insert(I); 2417b6f760fSDavid Green 2427b6f760fSDavid Green for (Use &Op : I->operands()) { 243*dd31b2c6SDavid Green if (!isa<FixedVectorType>(Op->getType())) 244*dd31b2c6SDavid Green continue; 2457b6f760fSDavid Green if (isa<Instruction>(Op)) 2467b6f760fSDavid Green Worklist.push_back(cast<Instruction>(&Op)); 2477b6f760fSDavid Green else 2483a68c6d2SDavid Green OtherLeafs.insert(&Op); 2497b6f760fSDavid Green } 2507b6f760fSDavid Green 2517b6f760fSDavid Green for (auto *Use : I->users()) 2527b6f760fSDavid Green Worklist.push_back(cast<Instruction>(Use)); 2537b6f760fSDavid Green break; 2547b6f760fSDavid Green 255d4b3380dSDavid Green case Instruction::ShuffleVector: 256d4b3380dSDavid Green // A shuffle of a splat is a splat. 257d4b3380dSDavid Green if (cast<ShuffleVectorInst>(I)->isZeroEltSplat()) 258d4b3380dSDavid Green continue; 259d4b3380dSDavid Green LLVM_FALLTHROUGH; 260d4b3380dSDavid Green 2617b6f760fSDavid Green default: 2627b6f760fSDavid Green LLVM_DEBUG(dbgs() << " Unhandled instruction: " << *I << "\n"); 2637b6f760fSDavid Green return false; 2647b6f760fSDavid Green } 2657b6f760fSDavid Green } 2667b6f760fSDavid Green 2673a68c6d2SDavid Green if (Exts.empty() && OtherLeafs.empty()) 2683a68c6d2SDavid Green return false; 2693a68c6d2SDavid Green 2707b6f760fSDavid Green LLVM_DEBUG({ 2717b6f760fSDavid Green dbgs() << "Found group:\n Exts:"; 2727b6f760fSDavid Green for (auto *I : Exts) 2737b6f760fSDavid Green dbgs() << " " << *I << "\n"; 2747b6f760fSDavid Green dbgs() << " Ops:"; 2757b6f760fSDavid Green for (auto *I : Ops) 2767b6f760fSDavid Green dbgs() << " " << *I << "\n"; 2773a68c6d2SDavid Green dbgs() << " OtherLeafs:"; 2783a68c6d2SDavid Green for (auto *I : OtherLeafs) 279*dd31b2c6SDavid Green dbgs() << " " << *I->get() << " of " << *I->getUser() << "\n"; 2807b6f760fSDavid Green dbgs() << "Truncs:"; 2817b6f760fSDavid Green for (auto *I : Truncs) 2827b6f760fSDavid Green dbgs() << " " << *I << "\n"; 2837b6f760fSDavid Green }); 2847b6f760fSDavid Green 2857b6f760fSDavid Green assert(!Truncs.empty() && "Expected some truncs"); 2867b6f760fSDavid Green 2877b6f760fSDavid Green // Check types 2887b6f760fSDavid Green unsigned NumElts = VT->getNumElements(); 2897b6f760fSDavid Green unsigned BaseElts = VT->getScalarSizeInBits() == 16 2907b6f760fSDavid Green ? 8 2917b6f760fSDavid Green : (VT->getScalarSizeInBits() == 8 ? 16 : 0); 2927b6f760fSDavid Green if (BaseElts == 0 || NumElts % BaseElts != 0) { 2937b6f760fSDavid Green LLVM_DEBUG(dbgs() << " Type is unsupported\n"); 2947b6f760fSDavid Green return false; 2957b6f760fSDavid Green } 2967b6f760fSDavid Green if (Start->getOperand(0)->getType()->getScalarSizeInBits() != 2977b6f760fSDavid Green VT->getScalarSizeInBits() * 2) { 2987b6f760fSDavid Green LLVM_DEBUG(dbgs() << " Type not double sized\n"); 2997b6f760fSDavid Green return false; 3007b6f760fSDavid Green } 3017b6f760fSDavid Green for (Instruction *I : Exts) 3027b6f760fSDavid Green if (I->getOperand(0)->getType() != VT) { 3037b6f760fSDavid Green LLVM_DEBUG(dbgs() << " Wrong type on " << *I << "\n"); 3047b6f760fSDavid Green return false; 3057b6f760fSDavid Green } 3067b6f760fSDavid Green for (Instruction *I : Truncs) 3077b6f760fSDavid Green if (I->getType() != VT) { 3087b6f760fSDavid Green LLVM_DEBUG(dbgs() << " Wrong type on " << *I << "\n"); 3097b6f760fSDavid Green return false; 3107b6f760fSDavid Green } 3117b6f760fSDavid Green 3127b6f760fSDavid Green // Check that it looks beneficial 3137b6f760fSDavid Green if (!isProfitableToInterleave(Exts, Truncs)) 3147b6f760fSDavid Green return false; 3157b6f760fSDavid Green 3167b6f760fSDavid Green // Create new shuffles around the extends / truncs / other leaves. 3177b6f760fSDavid Green IRBuilder<> Builder(Start); 3187b6f760fSDavid Green 3197b6f760fSDavid Green SmallVector<int, 16> LeafMask; 3207b6f760fSDavid Green SmallVector<int, 16> TruncMask; 3217b6f760fSDavid Green // LeafMask : 0, 2, 4, 6, 1, 3, 5, 7 8, 10, 12, 14, 9, 11, 13, 15 3227b6f760fSDavid Green // TruncMask: 0, 4, 1, 5, 2, 6, 3, 7 8, 12, 9, 13, 10, 14, 11, 15 3237b6f760fSDavid Green for (unsigned Base = 0; Base < NumElts; Base += BaseElts) { 3247b6f760fSDavid Green for (unsigned i = 0; i < BaseElts / 2; i++) 3257b6f760fSDavid Green LeafMask.push_back(Base + i * 2); 3267b6f760fSDavid Green for (unsigned i = 0; i < BaseElts / 2; i++) 3277b6f760fSDavid Green LeafMask.push_back(Base + i * 2 + 1); 3287b6f760fSDavid Green } 3297b6f760fSDavid Green for (unsigned Base = 0; Base < NumElts; Base += BaseElts) { 3307b6f760fSDavid Green for (unsigned i = 0; i < BaseElts / 2; i++) { 3317b6f760fSDavid Green TruncMask.push_back(Base + i); 3327b6f760fSDavid Green TruncMask.push_back(Base + i + BaseElts / 2); 3337b6f760fSDavid Green } 3347b6f760fSDavid Green } 3357b6f760fSDavid Green 3367b6f760fSDavid Green for (Instruction *I : Exts) { 3377b6f760fSDavid Green LLVM_DEBUG(dbgs() << "Replacing ext " << *I << "\n"); 3387b6f760fSDavid Green Builder.SetInsertPoint(I); 3397b6f760fSDavid Green Value *Shuffle = Builder.CreateShuffleVector(I->getOperand(0), LeafMask); 3406c0a1ed3SDavid Green bool FPext = isa<FPExtInst>(I); 3417b6f760fSDavid Green bool Sext = isa<SExtInst>(I); 3426c0a1ed3SDavid Green Value *Ext = FPext ? Builder.CreateFPExt(Shuffle, I->getType()) 3436c0a1ed3SDavid Green : Sext ? Builder.CreateSExt(Shuffle, I->getType()) 3447b6f760fSDavid Green : Builder.CreateZExt(Shuffle, I->getType()); 3457b6f760fSDavid Green I->replaceAllUsesWith(Ext); 3467b6f760fSDavid Green LLVM_DEBUG(dbgs() << " with " << *Shuffle << "\n"); 3477b6f760fSDavid Green } 3487b6f760fSDavid Green 3493a68c6d2SDavid Green for (Use *I : OtherLeafs) { 3503a68c6d2SDavid Green LLVM_DEBUG(dbgs() << "Replacing leaf " << *I << "\n"); 3513a68c6d2SDavid Green Builder.SetInsertPoint(cast<Instruction>(I->getUser())); 3523a68c6d2SDavid Green Value *Shuffle = Builder.CreateShuffleVector(I->get(), LeafMask); 3533a68c6d2SDavid Green I->getUser()->setOperand(I->getOperandNo(), Shuffle); 3543a68c6d2SDavid Green LLVM_DEBUG(dbgs() << " with " << *Shuffle << "\n"); 3553a68c6d2SDavid Green } 3563a68c6d2SDavid Green 3577b6f760fSDavid Green for (Instruction *I : Truncs) { 3587b6f760fSDavid Green LLVM_DEBUG(dbgs() << "Replacing trunc " << *I << "\n"); 3597b6f760fSDavid Green 3607b6f760fSDavid Green Builder.SetInsertPoint(I->getParent(), ++I->getIterator()); 3617b6f760fSDavid Green Value *Shuf = Builder.CreateShuffleVector(I, TruncMask); 3627b6f760fSDavid Green I->replaceAllUsesWith(Shuf); 3637b6f760fSDavid Green cast<Instruction>(Shuf)->setOperand(0, I); 3647b6f760fSDavid Green 3657b6f760fSDavid Green LLVM_DEBUG(dbgs() << " with " << *Shuf << "\n"); 3667b6f760fSDavid Green } 3677b6f760fSDavid Green 3686c88ffedSDavid Green return true; 3697b6f760fSDavid Green } 3707b6f760fSDavid Green 3717b6f760fSDavid Green bool MVELaneInterleaving::runOnFunction(Function &F) { 3727b6f760fSDavid Green if (!EnableInterleave) 3737b6f760fSDavid Green return false; 3747b6f760fSDavid Green auto &TPC = getAnalysis<TargetPassConfig>(); 3757b6f760fSDavid Green auto &TM = TPC.getTM<TargetMachine>(); 3767b6f760fSDavid Green auto *ST = &TM.getSubtarget<ARMSubtarget>(F); 3777b6f760fSDavid Green if (!ST->hasMVEIntegerOps()) 3787b6f760fSDavid Green return false; 3797b6f760fSDavid Green 3807b6f760fSDavid Green bool Changed = false; 3817b6f760fSDavid Green 3827b6f760fSDavid Green SmallPtrSet<Instruction *, 16> Visited; 3837b6f760fSDavid Green for (Instruction &I : reverse(instructions(F))) { 3847b6f760fSDavid Green if (I.getType()->isVectorTy() && 3857b6f760fSDavid Green (isa<TruncInst>(I) || isa<FPTruncInst>(I)) && !Visited.count(&I)) 3867b6f760fSDavid Green Changed |= tryInterleave(&I, Visited); 3877b6f760fSDavid Green } 3887b6f760fSDavid Green 3897b6f760fSDavid Green return Changed; 3907b6f760fSDavid Green } 391