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"
48ed98c1b3Sserge-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
MVELaneInterleaving()897b6f760fSDavid Green explicit MVELaneInterleaving() : FunctionPass(ID) {
907b6f760fSDavid Green initializeMVELaneInterleavingPass(*PassRegistry::getPassRegistry());
917b6f760fSDavid Green }
927b6f760fSDavid Green
937b6f760fSDavid Green bool runOnFunction(Function &F) override;
947b6f760fSDavid Green
getPassName() const957b6f760fSDavid Green StringRef getPassName() const override { return "MVE lane interleaving"; }
967b6f760fSDavid Green
getAnalysisUsage(AnalysisUsage & AU) const977b6f760fSDavid 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
createMVELaneInterleavingPass()1117b6f760fSDavid Green Pass *llvm::createMVELaneInterleavingPass() {
1127b6f760fSDavid Green return new MVELaneInterleaving();
1137b6f760fSDavid Green }
1147b6f760fSDavid Green
isProfitableToInterleave(SmallSetVector<Instruction *,4> & Exts,SmallSetVector<Instruction *,4> & Truncs)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
tryInterleave(Instruction * Start,SmallPtrSetImpl<Instruction * > & Visited)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:
180*b254d671SKazu Hirata if (!Truncs.insert(I))
1817b6f760fSDavid Green continue;
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
196dd31b2c6SDavid Green case Instruction::Call: {
197dd31b2c6SDavid Green IntrinsicInst *II = dyn_cast<IntrinsicInst>(I);
198dd31b2c6SDavid Green if (!II)
199dd31b2c6SDavid Green return false;
200dd31b2c6SDavid Green
201dd31b2c6SDavid Green switch (II->getIntrinsicID()) {
202dd31b2c6SDavid Green case Intrinsic::abs:
203dd31b2c6SDavid Green case Intrinsic::smin:
204dd31b2c6SDavid Green case Intrinsic::smax:
205dd31b2c6SDavid Green case Intrinsic::umin:
206dd31b2c6SDavid Green case Intrinsic::umax:
207dd31b2c6SDavid Green case Intrinsic::sadd_sat:
208dd31b2c6SDavid Green case Intrinsic::ssub_sat:
209dd31b2c6SDavid Green case Intrinsic::uadd_sat:
210dd31b2c6SDavid Green case Intrinsic::usub_sat:
211dd31b2c6SDavid Green case Intrinsic::minnum:
212dd31b2c6SDavid Green case Intrinsic::maxnum:
213dd31b2c6SDavid Green case Intrinsic::fabs:
214dd31b2c6SDavid Green case Intrinsic::fma:
215dd31b2c6SDavid Green case Intrinsic::ceil:
216dd31b2c6SDavid Green case Intrinsic::floor:
217dd31b2c6SDavid Green case Intrinsic::rint:
218dd31b2c6SDavid Green case Intrinsic::round:
219dd31b2c6SDavid Green case Intrinsic::trunc:
220dd31b2c6SDavid Green break;
221dd31b2c6SDavid Green default:
222dd31b2c6SDavid Green return false;
223dd31b2c6SDavid Green }
224dd31b2c6SDavid Green LLVM_FALLTHROUGH; // Fall through to treating these like an operator below.
225dd31b2c6SDavid 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:
238*b254d671SKazu Hirata if (!Ops.insert(I))
2397b6f760fSDavid Green continue;
2407b6f760fSDavid Green
2417b6f760fSDavid Green for (Use &Op : I->operands()) {
242dd31b2c6SDavid Green if (!isa<FixedVectorType>(Op->getType()))
243dd31b2c6SDavid Green continue;
2447b6f760fSDavid Green if (isa<Instruction>(Op))
2457b6f760fSDavid Green Worklist.push_back(cast<Instruction>(&Op));
2467b6f760fSDavid Green else
2473a68c6d2SDavid Green OtherLeafs.insert(&Op);
2487b6f760fSDavid Green }
2497b6f760fSDavid Green
2507b6f760fSDavid Green for (auto *Use : I->users())
2517b6f760fSDavid Green Worklist.push_back(cast<Instruction>(Use));
2527b6f760fSDavid Green break;
2537b6f760fSDavid Green
254d4b3380dSDavid Green case Instruction::ShuffleVector:
255d4b3380dSDavid Green // A shuffle of a splat is a splat.
256d4b3380dSDavid Green if (cast<ShuffleVectorInst>(I)->isZeroEltSplat())
257d4b3380dSDavid Green continue;
258d4b3380dSDavid Green LLVM_FALLTHROUGH;
259d4b3380dSDavid Green
2607b6f760fSDavid Green default:
2617b6f760fSDavid Green LLVM_DEBUG(dbgs() << " Unhandled instruction: " << *I << "\n");
2627b6f760fSDavid Green return false;
2637b6f760fSDavid Green }
2647b6f760fSDavid Green }
2657b6f760fSDavid Green
2663a68c6d2SDavid Green if (Exts.empty() && OtherLeafs.empty())
2673a68c6d2SDavid Green return false;
2683a68c6d2SDavid Green
2697b6f760fSDavid Green LLVM_DEBUG({
2707b6f760fSDavid Green dbgs() << "Found group:\n Exts:";
2717b6f760fSDavid Green for (auto *I : Exts)
2727b6f760fSDavid Green dbgs() << " " << *I << "\n";
2737b6f760fSDavid Green dbgs() << " Ops:";
2747b6f760fSDavid Green for (auto *I : Ops)
2757b6f760fSDavid Green dbgs() << " " << *I << "\n";
2763a68c6d2SDavid Green dbgs() << " OtherLeafs:";
2773a68c6d2SDavid Green for (auto *I : OtherLeafs)
278dd31b2c6SDavid Green dbgs() << " " << *I->get() << " of " << *I->getUser() << "\n";
2797b6f760fSDavid Green dbgs() << "Truncs:";
2807b6f760fSDavid Green for (auto *I : Truncs)
2817b6f760fSDavid Green dbgs() << " " << *I << "\n";
2827b6f760fSDavid Green });
2837b6f760fSDavid Green
2847b6f760fSDavid Green assert(!Truncs.empty() && "Expected some truncs");
2857b6f760fSDavid Green
2867b6f760fSDavid Green // Check types
2877b6f760fSDavid Green unsigned NumElts = VT->getNumElements();
2887b6f760fSDavid Green unsigned BaseElts = VT->getScalarSizeInBits() == 16
2897b6f760fSDavid Green ? 8
2907b6f760fSDavid Green : (VT->getScalarSizeInBits() == 8 ? 16 : 0);
2917b6f760fSDavid Green if (BaseElts == 0 || NumElts % BaseElts != 0) {
2927b6f760fSDavid Green LLVM_DEBUG(dbgs() << " Type is unsupported\n");
2937b6f760fSDavid Green return false;
2947b6f760fSDavid Green }
2957b6f760fSDavid Green if (Start->getOperand(0)->getType()->getScalarSizeInBits() !=
2967b6f760fSDavid Green VT->getScalarSizeInBits() * 2) {
2977b6f760fSDavid Green LLVM_DEBUG(dbgs() << " Type not double sized\n");
2987b6f760fSDavid Green return false;
2997b6f760fSDavid Green }
3007b6f760fSDavid Green for (Instruction *I : Exts)
3017b6f760fSDavid Green if (I->getOperand(0)->getType() != VT) {
3027b6f760fSDavid Green LLVM_DEBUG(dbgs() << " Wrong type on " << *I << "\n");
3037b6f760fSDavid Green return false;
3047b6f760fSDavid Green }
3057b6f760fSDavid Green for (Instruction *I : Truncs)
3067b6f760fSDavid Green if (I->getType() != VT) {
3077b6f760fSDavid Green LLVM_DEBUG(dbgs() << " Wrong type on " << *I << "\n");
3087b6f760fSDavid Green return false;
3097b6f760fSDavid Green }
3107b6f760fSDavid Green
3117b6f760fSDavid Green // Check that it looks beneficial
3127b6f760fSDavid Green if (!isProfitableToInterleave(Exts, Truncs))
3137b6f760fSDavid Green return false;
3147b6f760fSDavid Green
3157b6f760fSDavid Green // Create new shuffles around the extends / truncs / other leaves.
3167b6f760fSDavid Green IRBuilder<> Builder(Start);
3177b6f760fSDavid Green
3187b6f760fSDavid Green SmallVector<int, 16> LeafMask;
3197b6f760fSDavid Green SmallVector<int, 16> TruncMask;
3207b6f760fSDavid Green // LeafMask : 0, 2, 4, 6, 1, 3, 5, 7 8, 10, 12, 14, 9, 11, 13, 15
3217b6f760fSDavid Green // TruncMask: 0, 4, 1, 5, 2, 6, 3, 7 8, 12, 9, 13, 10, 14, 11, 15
3227b6f760fSDavid Green for (unsigned Base = 0; Base < NumElts; Base += BaseElts) {
3237b6f760fSDavid Green for (unsigned i = 0; i < BaseElts / 2; i++)
3247b6f760fSDavid Green LeafMask.push_back(Base + i * 2);
3257b6f760fSDavid Green for (unsigned i = 0; i < BaseElts / 2; i++)
3267b6f760fSDavid Green LeafMask.push_back(Base + i * 2 + 1);
3277b6f760fSDavid Green }
3287b6f760fSDavid Green for (unsigned Base = 0; Base < NumElts; Base += BaseElts) {
3297b6f760fSDavid Green for (unsigned i = 0; i < BaseElts / 2; i++) {
3307b6f760fSDavid Green TruncMask.push_back(Base + i);
3317b6f760fSDavid Green TruncMask.push_back(Base + i + BaseElts / 2);
3327b6f760fSDavid Green }
3337b6f760fSDavid Green }
3347b6f760fSDavid Green
3357b6f760fSDavid Green for (Instruction *I : Exts) {
3367b6f760fSDavid Green LLVM_DEBUG(dbgs() << "Replacing ext " << *I << "\n");
3377b6f760fSDavid Green Builder.SetInsertPoint(I);
3387b6f760fSDavid Green Value *Shuffle = Builder.CreateShuffleVector(I->getOperand(0), LeafMask);
3396c0a1ed3SDavid Green bool FPext = isa<FPExtInst>(I);
3407b6f760fSDavid Green bool Sext = isa<SExtInst>(I);
3416c0a1ed3SDavid Green Value *Ext = FPext ? Builder.CreateFPExt(Shuffle, I->getType())
3426c0a1ed3SDavid Green : Sext ? Builder.CreateSExt(Shuffle, I->getType())
3437b6f760fSDavid Green : Builder.CreateZExt(Shuffle, I->getType());
3447b6f760fSDavid Green I->replaceAllUsesWith(Ext);
3457b6f760fSDavid Green LLVM_DEBUG(dbgs() << " with " << *Shuffle << "\n");
3467b6f760fSDavid Green }
3477b6f760fSDavid Green
3483a68c6d2SDavid Green for (Use *I : OtherLeafs) {
3493a68c6d2SDavid Green LLVM_DEBUG(dbgs() << "Replacing leaf " << *I << "\n");
3503a68c6d2SDavid Green Builder.SetInsertPoint(cast<Instruction>(I->getUser()));
3513a68c6d2SDavid Green Value *Shuffle = Builder.CreateShuffleVector(I->get(), LeafMask);
3523a68c6d2SDavid Green I->getUser()->setOperand(I->getOperandNo(), Shuffle);
3533a68c6d2SDavid Green LLVM_DEBUG(dbgs() << " with " << *Shuffle << "\n");
3543a68c6d2SDavid Green }
3553a68c6d2SDavid Green
3567b6f760fSDavid Green for (Instruction *I : Truncs) {
3577b6f760fSDavid Green LLVM_DEBUG(dbgs() << "Replacing trunc " << *I << "\n");
3587b6f760fSDavid Green
3597b6f760fSDavid Green Builder.SetInsertPoint(I->getParent(), ++I->getIterator());
3607b6f760fSDavid Green Value *Shuf = Builder.CreateShuffleVector(I, TruncMask);
3617b6f760fSDavid Green I->replaceAllUsesWith(Shuf);
3627b6f760fSDavid Green cast<Instruction>(Shuf)->setOperand(0, I);
3637b6f760fSDavid Green
3647b6f760fSDavid Green LLVM_DEBUG(dbgs() << " with " << *Shuf << "\n");
3657b6f760fSDavid Green }
3667b6f760fSDavid Green
3676c88ffedSDavid Green return true;
3687b6f760fSDavid Green }
3697b6f760fSDavid Green
runOnFunction(Function & F)3707b6f760fSDavid Green bool MVELaneInterleaving::runOnFunction(Function &F) {
3717b6f760fSDavid Green if (!EnableInterleave)
3727b6f760fSDavid Green return false;
3737b6f760fSDavid Green auto &TPC = getAnalysis<TargetPassConfig>();
3747b6f760fSDavid Green auto &TM = TPC.getTM<TargetMachine>();
3757b6f760fSDavid Green auto *ST = &TM.getSubtarget<ARMSubtarget>(F);
3767b6f760fSDavid Green if (!ST->hasMVEIntegerOps())
3777b6f760fSDavid Green return false;
3787b6f760fSDavid Green
3797b6f760fSDavid Green bool Changed = false;
3807b6f760fSDavid Green
3817b6f760fSDavid Green SmallPtrSet<Instruction *, 16> Visited;
3827b6f760fSDavid Green for (Instruction &I : reverse(instructions(F))) {
3837b6f760fSDavid Green if (I.getType()->isVectorTy() &&
3847b6f760fSDavid Green (isa<TruncInst>(I) || isa<FPTruncInst>(I)) && !Visited.count(&I))
3857b6f760fSDavid Green Changed |= tryInterleave(&I, Visited);
3867b6f760fSDavid Green }
3877b6f760fSDavid Green
3887b6f760fSDavid Green return Changed;
3897b6f760fSDavid Green }
390