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" 48*ed98c1b3Sserge-sans-paille #include "llvm/ADT/SetVector.h" 497b6f760fSDavid Green #include "llvm/Analysis/TargetTransformInfo.h" 507b6f760fSDavid Green #include "llvm/CodeGen/TargetLowering.h" 517b6f760fSDavid Green #include "llvm/CodeGen/TargetPassConfig.h" 527b6f760fSDavid Green #include "llvm/CodeGen/TargetSubtargetInfo.h" 537b6f760fSDavid Green #include "llvm/IR/BasicBlock.h" 547b6f760fSDavid Green #include "llvm/IR/Constant.h" 557b6f760fSDavid Green #include "llvm/IR/Constants.h" 567b6f760fSDavid Green #include "llvm/IR/DerivedTypes.h" 577b6f760fSDavid Green #include "llvm/IR/Function.h" 587b6f760fSDavid Green #include "llvm/IR/IRBuilder.h" 597b6f760fSDavid Green #include "llvm/IR/InstIterator.h" 607b6f760fSDavid Green #include "llvm/IR/InstrTypes.h" 617b6f760fSDavid Green #include "llvm/IR/Instruction.h" 627b6f760fSDavid Green #include "llvm/IR/Instructions.h" 637b6f760fSDavid Green #include "llvm/IR/IntrinsicInst.h" 647b6f760fSDavid Green #include "llvm/IR/Intrinsics.h" 657b6f760fSDavid Green #include "llvm/IR/IntrinsicsARM.h" 667b6f760fSDavid Green #include "llvm/IR/PatternMatch.h" 677b6f760fSDavid Green #include "llvm/IR/Type.h" 687b6f760fSDavid Green #include "llvm/IR/Value.h" 697b6f760fSDavid Green #include "llvm/InitializePasses.h" 707b6f760fSDavid Green #include "llvm/Pass.h" 717b6f760fSDavid Green #include "llvm/Support/Casting.h" 727b6f760fSDavid Green #include <algorithm> 737b6f760fSDavid Green #include <cassert> 747b6f760fSDavid Green 757b6f760fSDavid Green using namespace llvm; 767b6f760fSDavid Green 777b6f760fSDavid Green #define DEBUG_TYPE "mve-laneinterleave" 787b6f760fSDavid Green 797b6f760fSDavid Green cl::opt<bool> EnableInterleave( 807b6f760fSDavid Green "enable-mve-interleave", cl::Hidden, cl::init(true), 817b6f760fSDavid Green cl::desc("Enable interleave MVE vector operation lowering")); 827b6f760fSDavid Green 837b6f760fSDavid Green namespace { 847b6f760fSDavid Green 857b6f760fSDavid Green class MVELaneInterleaving : public FunctionPass { 867b6f760fSDavid Green public: 877b6f760fSDavid Green static char ID; // Pass identification, replacement for typeid 887b6f760fSDavid Green 897b6f760fSDavid Green explicit MVELaneInterleaving() : FunctionPass(ID) { 907b6f760fSDavid Green initializeMVELaneInterleavingPass(*PassRegistry::getPassRegistry()); 917b6f760fSDavid Green } 927b6f760fSDavid Green 937b6f760fSDavid Green bool runOnFunction(Function &F) override; 947b6f760fSDavid Green 957b6f760fSDavid Green StringRef getPassName() const override { return "MVE lane interleaving"; } 967b6f760fSDavid Green 977b6f760fSDavid Green void getAnalysisUsage(AnalysisUsage &AU) const override { 987b6f760fSDavid Green AU.setPreservesCFG(); 997b6f760fSDavid Green AU.addRequired<TargetPassConfig>(); 1007b6f760fSDavid Green FunctionPass::getAnalysisUsage(AU); 1017b6f760fSDavid Green } 1027b6f760fSDavid Green }; 1037b6f760fSDavid Green 1047b6f760fSDavid Green } // end anonymous namespace 1057b6f760fSDavid Green 1067b6f760fSDavid Green char MVELaneInterleaving::ID = 0; 1077b6f760fSDavid Green 1087b6f760fSDavid Green INITIALIZE_PASS(MVELaneInterleaving, DEBUG_TYPE, "MVE lane interleaving", false, 1097b6f760fSDavid Green false) 1107b6f760fSDavid Green 1117b6f760fSDavid Green Pass *llvm::createMVELaneInterleavingPass() { 1127b6f760fSDavid Green return new MVELaneInterleaving(); 1137b6f760fSDavid Green } 1147b6f760fSDavid Green 1157b6f760fSDavid Green static bool isProfitableToInterleave(SmallSetVector<Instruction *, 4> &Exts, 1167b6f760fSDavid Green SmallSetVector<Instruction *, 4> &Truncs) { 1177b6f760fSDavid Green // This is not always beneficial to transform. Exts can be incorporated into 1187b6f760fSDavid Green // loads, Truncs can be folded into stores. 1197b6f760fSDavid Green // Truncs are usually the same number of instructions, 1207b6f760fSDavid Green // VSTRH.32(A);VSTRH.32(B) vs VSTRH.16(VMOVNT A, B) with interleaving 1217b6f760fSDavid Green // Exts are unfortunately more instructions in the general case: 1227b6f760fSDavid Green // A=VLDRH.32; B=VLDRH.32; 1237b6f760fSDavid Green // vs with interleaving: 1247b6f760fSDavid Green // T=VLDRH.16; A=VMOVNB T; B=VMOVNT T 1257b6f760fSDavid Green // But those VMOVL may be folded into a VMULL. 1267b6f760fSDavid Green 1276c0a1ed3SDavid Green // But expensive extends/truncs are always good to remove. FPExts always 1286c0a1ed3SDavid Green // involve extra VCVT's so are always considered to be beneficial to convert. 1296c0a1ed3SDavid Green for (auto *E : Exts) { 1306c0a1ed3SDavid Green if (isa<FPExtInst>(E) || !isa<LoadInst>(E->getOperand(0))) { 1317b6f760fSDavid Green LLVM_DEBUG(dbgs() << "Beneficial due to " << *E << "\n"); 1327b6f760fSDavid Green return true; 1337b6f760fSDavid Green } 1346c0a1ed3SDavid Green } 1356c0a1ed3SDavid Green for (auto *T : Truncs) { 1367b6f760fSDavid Green if (T->hasOneUse() && !isa<StoreInst>(*T->user_begin())) { 1377b6f760fSDavid Green LLVM_DEBUG(dbgs() << "Beneficial due to " << *T << "\n"); 1387b6f760fSDavid Green return true; 1397b6f760fSDavid Green } 1406c0a1ed3SDavid Green } 1417b6f760fSDavid Green 1427b6f760fSDavid Green // Otherwise, we know we have a load(ext), see if any of the Extends are a 1437b6f760fSDavid Green // vmull. This is a simple heuristic and certainly not perfect. 1447b6f760fSDavid Green for (auto *E : Exts) { 1457b6f760fSDavid Green if (!E->hasOneUse() || 1467b6f760fSDavid Green cast<Instruction>(*E->user_begin())->getOpcode() != Instruction::Mul) { 1477b6f760fSDavid Green LLVM_DEBUG(dbgs() << "Not beneficial due to " << *E << "\n"); 1487b6f760fSDavid Green return false; 1497b6f760fSDavid Green } 1507b6f760fSDavid Green } 1517b6f760fSDavid Green return true; 1527b6f760fSDavid Green } 1537b6f760fSDavid Green 1547b6f760fSDavid Green static bool tryInterleave(Instruction *Start, 1557b6f760fSDavid Green SmallPtrSetImpl<Instruction *> &Visited) { 1567b6f760fSDavid Green LLVM_DEBUG(dbgs() << "tryInterleave from " << *Start << "\n"); 1577b6f760fSDavid Green auto *VT = cast<FixedVectorType>(Start->getType()); 1587b6f760fSDavid Green 1597b6f760fSDavid Green if (!isa<Instruction>(Start->getOperand(0))) 1607b6f760fSDavid Green return false; 1617b6f760fSDavid Green 1627b6f760fSDavid Green // Look for connected operations starting from Ext's, terminating at Truncs. 1637b6f760fSDavid Green std::vector<Instruction *> Worklist; 1647b6f760fSDavid Green Worklist.push_back(Start); 1657b6f760fSDavid Green Worklist.push_back(cast<Instruction>(Start->getOperand(0))); 1667b6f760fSDavid Green 1677b6f760fSDavid Green SmallSetVector<Instruction *, 4> Truncs; 1687b6f760fSDavid Green SmallSetVector<Instruction *, 4> Exts; 1693a68c6d2SDavid Green SmallSetVector<Use *, 4> OtherLeafs; 1707b6f760fSDavid Green SmallSetVector<Instruction *, 4> Ops; 1717b6f760fSDavid Green 1727b6f760fSDavid Green while (!Worklist.empty()) { 1737b6f760fSDavid Green Instruction *I = Worklist.back(); 1747b6f760fSDavid Green Worklist.pop_back(); 1757b6f760fSDavid Green 1767b6f760fSDavid Green switch (I->getOpcode()) { 1777b6f760fSDavid Green // Truncs 1787b6f760fSDavid Green case Instruction::Trunc: 1796c0a1ed3SDavid Green case Instruction::FPTrunc: 1807b6f760fSDavid Green if (Truncs.count(I)) 1817b6f760fSDavid Green continue; 1827b6f760fSDavid Green Truncs.insert(I); 1837b6f760fSDavid Green Visited.insert(I); 1847b6f760fSDavid Green break; 1857b6f760fSDavid Green 1867b6f760fSDavid Green // Extend leafs 1877b6f760fSDavid Green case Instruction::SExt: 1887b6f760fSDavid Green case Instruction::ZExt: 1896c0a1ed3SDavid Green case Instruction::FPExt: 1907b6f760fSDavid Green if (Exts.count(I)) 1917b6f760fSDavid Green continue; 1927b6f760fSDavid Green for (auto *Use : I->users()) 1937b6f760fSDavid Green Worklist.push_back(cast<Instruction>(Use)); 1947b6f760fSDavid Green Exts.insert(I); 1957b6f760fSDavid Green break; 1967b6f760fSDavid Green 197dd31b2c6SDavid Green case Instruction::Call: { 198dd31b2c6SDavid Green IntrinsicInst *II = dyn_cast<IntrinsicInst>(I); 199dd31b2c6SDavid Green if (!II) 200dd31b2c6SDavid Green return false; 201dd31b2c6SDavid Green 202dd31b2c6SDavid Green switch (II->getIntrinsicID()) { 203dd31b2c6SDavid Green case Intrinsic::abs: 204dd31b2c6SDavid Green case Intrinsic::smin: 205dd31b2c6SDavid Green case Intrinsic::smax: 206dd31b2c6SDavid Green case Intrinsic::umin: 207dd31b2c6SDavid Green case Intrinsic::umax: 208dd31b2c6SDavid Green case Intrinsic::sadd_sat: 209dd31b2c6SDavid Green case Intrinsic::ssub_sat: 210dd31b2c6SDavid Green case Intrinsic::uadd_sat: 211dd31b2c6SDavid Green case Intrinsic::usub_sat: 212dd31b2c6SDavid Green case Intrinsic::minnum: 213dd31b2c6SDavid Green case Intrinsic::maxnum: 214dd31b2c6SDavid Green case Intrinsic::fabs: 215dd31b2c6SDavid Green case Intrinsic::fma: 216dd31b2c6SDavid Green case Intrinsic::ceil: 217dd31b2c6SDavid Green case Intrinsic::floor: 218dd31b2c6SDavid Green case Intrinsic::rint: 219dd31b2c6SDavid Green case Intrinsic::round: 220dd31b2c6SDavid Green case Intrinsic::trunc: 221dd31b2c6SDavid Green break; 222dd31b2c6SDavid Green default: 223dd31b2c6SDavid Green return false; 224dd31b2c6SDavid Green } 225dd31b2c6SDavid Green LLVM_FALLTHROUGH; // Fall through to treating these like an operator below. 226dd31b2c6SDavid Green } 2277b6f760fSDavid Green // Binary/tertiary ops 2287b6f760fSDavid Green case Instruction::Add: 2297b6f760fSDavid Green case Instruction::Sub: 2307b6f760fSDavid Green case Instruction::Mul: 2317b6f760fSDavid Green case Instruction::AShr: 2327b6f760fSDavid Green case Instruction::LShr: 2337b6f760fSDavid Green case Instruction::Shl: 2347b6f760fSDavid Green case Instruction::ICmp: 2356c0a1ed3SDavid Green case Instruction::FCmp: 2366c0a1ed3SDavid Green case Instruction::FAdd: 2376c0a1ed3SDavid Green case Instruction::FMul: 2387b6f760fSDavid Green case Instruction::Select: 2397b6f760fSDavid Green if (Ops.count(I)) 2407b6f760fSDavid Green continue; 2417b6f760fSDavid Green Ops.insert(I); 2427b6f760fSDavid Green 2437b6f760fSDavid Green for (Use &Op : I->operands()) { 244dd31b2c6SDavid Green if (!isa<FixedVectorType>(Op->getType())) 245dd31b2c6SDavid Green continue; 2467b6f760fSDavid Green if (isa<Instruction>(Op)) 2477b6f760fSDavid Green Worklist.push_back(cast<Instruction>(&Op)); 2487b6f760fSDavid Green else 2493a68c6d2SDavid Green OtherLeafs.insert(&Op); 2507b6f760fSDavid Green } 2517b6f760fSDavid Green 2527b6f760fSDavid Green for (auto *Use : I->users()) 2537b6f760fSDavid Green Worklist.push_back(cast<Instruction>(Use)); 2547b6f760fSDavid Green break; 2557b6f760fSDavid Green 256d4b3380dSDavid Green case Instruction::ShuffleVector: 257d4b3380dSDavid Green // A shuffle of a splat is a splat. 258d4b3380dSDavid Green if (cast<ShuffleVectorInst>(I)->isZeroEltSplat()) 259d4b3380dSDavid Green continue; 260d4b3380dSDavid Green LLVM_FALLTHROUGH; 261d4b3380dSDavid Green 2627b6f760fSDavid Green default: 2637b6f760fSDavid Green LLVM_DEBUG(dbgs() << " Unhandled instruction: " << *I << "\n"); 2647b6f760fSDavid Green return false; 2657b6f760fSDavid Green } 2667b6f760fSDavid Green } 2677b6f760fSDavid Green 2683a68c6d2SDavid Green if (Exts.empty() && OtherLeafs.empty()) 2693a68c6d2SDavid Green return false; 2703a68c6d2SDavid Green 2717b6f760fSDavid Green LLVM_DEBUG({ 2727b6f760fSDavid Green dbgs() << "Found group:\n Exts:"; 2737b6f760fSDavid Green for (auto *I : Exts) 2747b6f760fSDavid Green dbgs() << " " << *I << "\n"; 2757b6f760fSDavid Green dbgs() << " Ops:"; 2767b6f760fSDavid Green for (auto *I : Ops) 2777b6f760fSDavid Green dbgs() << " " << *I << "\n"; 2783a68c6d2SDavid Green dbgs() << " OtherLeafs:"; 2793a68c6d2SDavid Green for (auto *I : OtherLeafs) 280dd31b2c6SDavid Green dbgs() << " " << *I->get() << " of " << *I->getUser() << "\n"; 2817b6f760fSDavid Green dbgs() << "Truncs:"; 2827b6f760fSDavid Green for (auto *I : Truncs) 2837b6f760fSDavid Green dbgs() << " " << *I << "\n"; 2847b6f760fSDavid Green }); 2857b6f760fSDavid Green 2867b6f760fSDavid Green assert(!Truncs.empty() && "Expected some truncs"); 2877b6f760fSDavid Green 2887b6f760fSDavid Green // Check types 2897b6f760fSDavid Green unsigned NumElts = VT->getNumElements(); 2907b6f760fSDavid Green unsigned BaseElts = VT->getScalarSizeInBits() == 16 2917b6f760fSDavid Green ? 8 2927b6f760fSDavid Green : (VT->getScalarSizeInBits() == 8 ? 16 : 0); 2937b6f760fSDavid Green if (BaseElts == 0 || NumElts % BaseElts != 0) { 2947b6f760fSDavid Green LLVM_DEBUG(dbgs() << " Type is unsupported\n"); 2957b6f760fSDavid Green return false; 2967b6f760fSDavid Green } 2977b6f760fSDavid Green if (Start->getOperand(0)->getType()->getScalarSizeInBits() != 2987b6f760fSDavid Green VT->getScalarSizeInBits() * 2) { 2997b6f760fSDavid Green LLVM_DEBUG(dbgs() << " Type not double sized\n"); 3007b6f760fSDavid Green return false; 3017b6f760fSDavid Green } 3027b6f760fSDavid Green for (Instruction *I : Exts) 3037b6f760fSDavid Green if (I->getOperand(0)->getType() != VT) { 3047b6f760fSDavid Green LLVM_DEBUG(dbgs() << " Wrong type on " << *I << "\n"); 3057b6f760fSDavid Green return false; 3067b6f760fSDavid Green } 3077b6f760fSDavid Green for (Instruction *I : Truncs) 3087b6f760fSDavid Green if (I->getType() != VT) { 3097b6f760fSDavid Green LLVM_DEBUG(dbgs() << " Wrong type on " << *I << "\n"); 3107b6f760fSDavid Green return false; 3117b6f760fSDavid Green } 3127b6f760fSDavid Green 3137b6f760fSDavid Green // Check that it looks beneficial 3147b6f760fSDavid Green if (!isProfitableToInterleave(Exts, Truncs)) 3157b6f760fSDavid Green return false; 3167b6f760fSDavid Green 3177b6f760fSDavid Green // Create new shuffles around the extends / truncs / other leaves. 3187b6f760fSDavid Green IRBuilder<> Builder(Start); 3197b6f760fSDavid Green 3207b6f760fSDavid Green SmallVector<int, 16> LeafMask; 3217b6f760fSDavid Green SmallVector<int, 16> TruncMask; 3227b6f760fSDavid Green // LeafMask : 0, 2, 4, 6, 1, 3, 5, 7 8, 10, 12, 14, 9, 11, 13, 15 3237b6f760fSDavid Green // TruncMask: 0, 4, 1, 5, 2, 6, 3, 7 8, 12, 9, 13, 10, 14, 11, 15 3247b6f760fSDavid Green for (unsigned Base = 0; Base < NumElts; Base += BaseElts) { 3257b6f760fSDavid Green for (unsigned i = 0; i < BaseElts / 2; i++) 3267b6f760fSDavid Green LeafMask.push_back(Base + i * 2); 3277b6f760fSDavid Green for (unsigned i = 0; i < BaseElts / 2; i++) 3287b6f760fSDavid Green LeafMask.push_back(Base + i * 2 + 1); 3297b6f760fSDavid Green } 3307b6f760fSDavid Green for (unsigned Base = 0; Base < NumElts; Base += BaseElts) { 3317b6f760fSDavid Green for (unsigned i = 0; i < BaseElts / 2; i++) { 3327b6f760fSDavid Green TruncMask.push_back(Base + i); 3337b6f760fSDavid Green TruncMask.push_back(Base + i + BaseElts / 2); 3347b6f760fSDavid Green } 3357b6f760fSDavid Green } 3367b6f760fSDavid Green 3377b6f760fSDavid Green for (Instruction *I : Exts) { 3387b6f760fSDavid Green LLVM_DEBUG(dbgs() << "Replacing ext " << *I << "\n"); 3397b6f760fSDavid Green Builder.SetInsertPoint(I); 3407b6f760fSDavid Green Value *Shuffle = Builder.CreateShuffleVector(I->getOperand(0), LeafMask); 3416c0a1ed3SDavid Green bool FPext = isa<FPExtInst>(I); 3427b6f760fSDavid Green bool Sext = isa<SExtInst>(I); 3436c0a1ed3SDavid Green Value *Ext = FPext ? Builder.CreateFPExt(Shuffle, I->getType()) 3446c0a1ed3SDavid Green : Sext ? Builder.CreateSExt(Shuffle, I->getType()) 3457b6f760fSDavid Green : Builder.CreateZExt(Shuffle, I->getType()); 3467b6f760fSDavid Green I->replaceAllUsesWith(Ext); 3477b6f760fSDavid Green LLVM_DEBUG(dbgs() << " with " << *Shuffle << "\n"); 3487b6f760fSDavid Green } 3497b6f760fSDavid Green 3503a68c6d2SDavid Green for (Use *I : OtherLeafs) { 3513a68c6d2SDavid Green LLVM_DEBUG(dbgs() << "Replacing leaf " << *I << "\n"); 3523a68c6d2SDavid Green Builder.SetInsertPoint(cast<Instruction>(I->getUser())); 3533a68c6d2SDavid Green Value *Shuffle = Builder.CreateShuffleVector(I->get(), LeafMask); 3543a68c6d2SDavid Green I->getUser()->setOperand(I->getOperandNo(), Shuffle); 3553a68c6d2SDavid Green LLVM_DEBUG(dbgs() << " with " << *Shuffle << "\n"); 3563a68c6d2SDavid Green } 3573a68c6d2SDavid Green 3587b6f760fSDavid Green for (Instruction *I : Truncs) { 3597b6f760fSDavid Green LLVM_DEBUG(dbgs() << "Replacing trunc " << *I << "\n"); 3607b6f760fSDavid Green 3617b6f760fSDavid Green Builder.SetInsertPoint(I->getParent(), ++I->getIterator()); 3627b6f760fSDavid Green Value *Shuf = Builder.CreateShuffleVector(I, TruncMask); 3637b6f760fSDavid Green I->replaceAllUsesWith(Shuf); 3647b6f760fSDavid Green cast<Instruction>(Shuf)->setOperand(0, I); 3657b6f760fSDavid Green 3667b6f760fSDavid Green LLVM_DEBUG(dbgs() << " with " << *Shuf << "\n"); 3677b6f760fSDavid Green } 3687b6f760fSDavid Green 3696c88ffedSDavid Green return true; 3707b6f760fSDavid Green } 3717b6f760fSDavid Green 3727b6f760fSDavid Green bool MVELaneInterleaving::runOnFunction(Function &F) { 3737b6f760fSDavid Green if (!EnableInterleave) 3747b6f760fSDavid Green return false; 3757b6f760fSDavid Green auto &TPC = getAnalysis<TargetPassConfig>(); 3767b6f760fSDavid Green auto &TM = TPC.getTM<TargetMachine>(); 3777b6f760fSDavid Green auto *ST = &TM.getSubtarget<ARMSubtarget>(F); 3787b6f760fSDavid Green if (!ST->hasMVEIntegerOps()) 3797b6f760fSDavid Green return false; 3807b6f760fSDavid Green 3817b6f760fSDavid Green bool Changed = false; 3827b6f760fSDavid Green 3837b6f760fSDavid Green SmallPtrSet<Instruction *, 16> Visited; 3847b6f760fSDavid Green for (Instruction &I : reverse(instructions(F))) { 3857b6f760fSDavid Green if (I.getType()->isVectorTy() && 3867b6f760fSDavid Green (isa<TruncInst>(I) || isa<FPTruncInst>(I)) && !Visited.count(&I)) 3877b6f760fSDavid Green Changed |= tryInterleave(&I, Visited); 3887b6f760fSDavid Green } 3897b6f760fSDavid Green 3907b6f760fSDavid Green return Changed; 3917b6f760fSDavid Green } 392