1 //===- MVEGatherScatterLowering.cpp - Gather/Scatter lowering -------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 /// This pass custom lowers llvm.gather and llvm.scatter instructions to
10 /// arm.mve.gather and arm.mve.scatter intrinsics, optimising the code to
11 /// produce a better final result as we go.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "ARM.h"
16 #include "ARMBaseInstrInfo.h"
17 #include "ARMSubtarget.h"
18 #include "llvm/Analysis/LoopInfo.h"
19 #include "llvm/Analysis/TargetTransformInfo.h"
20 #include "llvm/CodeGen/TargetLowering.h"
21 #include "llvm/CodeGen/TargetPassConfig.h"
22 #include "llvm/CodeGen/TargetSubtargetInfo.h"
23 #include "llvm/InitializePasses.h"
24 #include "llvm/IR/BasicBlock.h"
25 #include "llvm/IR/Constant.h"
26 #include "llvm/IR/Constants.h"
27 #include "llvm/IR/DerivedTypes.h"
28 #include "llvm/IR/Function.h"
29 #include "llvm/IR/InstrTypes.h"
30 #include "llvm/IR/Instruction.h"
31 #include "llvm/IR/Instructions.h"
32 #include "llvm/IR/IntrinsicInst.h"
33 #include "llvm/IR/Intrinsics.h"
34 #include "llvm/IR/IntrinsicsARM.h"
35 #include "llvm/IR/IRBuilder.h"
36 #include "llvm/IR/PatternMatch.h"
37 #include "llvm/IR/Type.h"
38 #include "llvm/IR/Value.h"
39 #include "llvm/Pass.h"
40 #include "llvm/Support/Casting.h"
41 #include "llvm/Transforms/Utils/Local.h"
42 #include <algorithm>
43 #include <cassert>
44 
45 using namespace llvm;
46 
47 #define DEBUG_TYPE "arm-mve-gather-scatter-lowering"
48 
49 cl::opt<bool> EnableMaskedGatherScatters(
50     "enable-arm-maskedgatscat", cl::Hidden, cl::init(true),
51     cl::desc("Enable the generation of masked gathers and scatters"));
52 
53 namespace {
54 
55 class MVEGatherScatterLowering : public FunctionPass {
56 public:
57   static char ID; // Pass identification, replacement for typeid
58 
59   explicit MVEGatherScatterLowering() : FunctionPass(ID) {
60     initializeMVEGatherScatterLoweringPass(*PassRegistry::getPassRegistry());
61   }
62 
63   bool runOnFunction(Function &F) override;
64 
65   StringRef getPassName() const override {
66     return "MVE gather/scatter lowering";
67   }
68 
69   void getAnalysisUsage(AnalysisUsage &AU) const override {
70     AU.setPreservesCFG();
71     AU.addRequired<TargetPassConfig>();
72     AU.addRequired<LoopInfoWrapperPass>();
73     FunctionPass::getAnalysisUsage(AU);
74   }
75 
76 private:
77   LoopInfo *LI = nullptr;
78 
79   // Check this is a valid gather with correct alignment
80   bool isLegalTypeAndAlignment(unsigned NumElements, unsigned ElemSize,
81                                Align Alignment);
82   // Check whether Ptr is hidden behind a bitcast and look through it
83   void lookThroughBitcast(Value *&Ptr);
84   // Decompose a ptr into Base and Offsets, potentially using a GEP to return a
85   // scalar base and vector offsets, or else fallback to using a base of 0 and
86   // offset of Ptr where possible.
87   Value *decomposePtr(Value *Ptr, Value *&Offsets, int &Scale,
88                       FixedVectorType *Ty, Type *MemoryTy,
89                       IRBuilder<> &Builder);
90   // Check for a getelementptr and deduce base and offsets from it, on success
91   // returning the base directly and the offsets indirectly using the Offsets
92   // argument
93   Value *decomposeGEP(Value *&Offsets, FixedVectorType *Ty,
94                       GetElementPtrInst *GEP, IRBuilder<> &Builder);
95   // Compute the scale of this gather/scatter instruction
96   int computeScale(unsigned GEPElemSize, unsigned MemoryElemSize);
97   // If the value is a constant, or derived from constants via additions
98   // and multilications, return its numeric value
99   Optional<int64_t> getIfConst(const Value *V);
100   // If Inst is an add instruction, check whether one summand is a
101   // constant. If so, scale this constant and return it together with
102   // the other summand.
103   std::pair<Value *, int64_t> getVarAndConst(Value *Inst, int TypeScale);
104 
105   Instruction *lowerGather(IntrinsicInst *I);
106   // Create a gather from a base + vector of offsets
107   Instruction *tryCreateMaskedGatherOffset(IntrinsicInst *I, Value *Ptr,
108                                            Instruction *&Root,
109                                            IRBuilder<> &Builder);
110   // Create a gather from a vector of pointers
111   Instruction *tryCreateMaskedGatherBase(IntrinsicInst *I, Value *Ptr,
112                                          IRBuilder<> &Builder,
113                                          int64_t Increment = 0);
114   // Create an incrementing gather from a vector of pointers
115   Instruction *tryCreateMaskedGatherBaseWB(IntrinsicInst *I, Value *Ptr,
116                                            IRBuilder<> &Builder,
117                                            int64_t Increment = 0);
118 
119   Instruction *lowerScatter(IntrinsicInst *I);
120   // Create a scatter to a base + vector of offsets
121   Instruction *tryCreateMaskedScatterOffset(IntrinsicInst *I, Value *Offsets,
122                                             IRBuilder<> &Builder);
123   // Create a scatter to a vector of pointers
124   Instruction *tryCreateMaskedScatterBase(IntrinsicInst *I, Value *Ptr,
125                                           IRBuilder<> &Builder,
126                                           int64_t Increment = 0);
127   // Create an incrementing scatter from a vector of pointers
128   Instruction *tryCreateMaskedScatterBaseWB(IntrinsicInst *I, Value *Ptr,
129                                             IRBuilder<> &Builder,
130                                             int64_t Increment = 0);
131 
132   // QI gathers and scatters can increment their offsets on their own if
133   // the increment is a constant value (digit)
134   Instruction *tryCreateIncrementingGatScat(IntrinsicInst *I, Value *Ptr,
135                                             IRBuilder<> &Builder);
136   // QI gathers/scatters can increment their offsets on their own if the
137   // increment is a constant value (digit) - this creates a writeback QI
138   // gather/scatter
139   Instruction *tryCreateIncrementingWBGatScat(IntrinsicInst *I, Value *BasePtr,
140                                               Value *Ptr, unsigned TypeScale,
141                                               IRBuilder<> &Builder);
142 
143   // Optimise the base and offsets of the given address
144   bool optimiseAddress(Value *Address, BasicBlock *BB, LoopInfo *LI);
145   // Try to fold consecutive geps together into one
146   Value *foldGEP(GetElementPtrInst *GEP, Value *&Offsets, IRBuilder<> &Builder);
147   // Check whether these offsets could be moved out of the loop they're in
148   bool optimiseOffsets(Value *Offsets, BasicBlock *BB, LoopInfo *LI);
149   // Pushes the given add out of the loop
150   void pushOutAdd(PHINode *&Phi, Value *OffsSecondOperand, unsigned StartIndex);
151   // Pushes the given mul out of the loop
152   void pushOutMul(PHINode *&Phi, Value *IncrementPerRound,
153                   Value *OffsSecondOperand, unsigned LoopIncrement,
154                   IRBuilder<> &Builder);
155 };
156 
157 } // end anonymous namespace
158 
159 char MVEGatherScatterLowering::ID = 0;
160 
161 INITIALIZE_PASS(MVEGatherScatterLowering, DEBUG_TYPE,
162                 "MVE gather/scattering lowering pass", false, false)
163 
164 Pass *llvm::createMVEGatherScatterLoweringPass() {
165   return new MVEGatherScatterLowering();
166 }
167 
168 bool MVEGatherScatterLowering::isLegalTypeAndAlignment(unsigned NumElements,
169                                                        unsigned ElemSize,
170                                                        Align Alignment) {
171   if (((NumElements == 4 &&
172         (ElemSize == 32 || ElemSize == 16 || ElemSize == 8)) ||
173        (NumElements == 8 && (ElemSize == 16 || ElemSize == 8)) ||
174        (NumElements == 16 && ElemSize == 8)) &&
175       Alignment >= ElemSize / 8)
176     return true;
177   LLVM_DEBUG(dbgs() << "masked gathers/scatters: instruction does not have "
178                     << "valid alignment or vector type \n");
179   return false;
180 }
181 
182 static bool checkOffsetSize(Value *Offsets, unsigned TargetElemCount) {
183   // Offsets that are not of type <N x i32> are sign extended by the
184   // getelementptr instruction, and MVE gathers/scatters treat the offset as
185   // unsigned. Thus, if the element size is smaller than 32, we can only allow
186   // positive offsets - i.e., the offsets are not allowed to be variables we
187   // can't look into.
188   // Additionally, <N x i32> offsets have to either originate from a zext of a
189   // vector with element types smaller or equal the type of the gather we're
190   // looking at, or consist of constants that we can check are small enough
191   // to fit into the gather type.
192   // Thus we check that 0 < value < 2^TargetElemSize.
193   unsigned TargetElemSize = 128 / TargetElemCount;
194   unsigned OffsetElemSize = cast<FixedVectorType>(Offsets->getType())
195                                 ->getElementType()
196                                 ->getScalarSizeInBits();
197   if (OffsetElemSize != TargetElemSize || OffsetElemSize != 32) {
198     Constant *ConstOff = dyn_cast<Constant>(Offsets);
199     if (!ConstOff)
200       return false;
201     int64_t TargetElemMaxSize = (1ULL << TargetElemSize);
202     auto CheckValueSize = [TargetElemMaxSize](Value *OffsetElem) {
203       ConstantInt *OConst = dyn_cast<ConstantInt>(OffsetElem);
204       if (!OConst)
205         return false;
206       int SExtValue = OConst->getSExtValue();
207       if (SExtValue >= TargetElemMaxSize || SExtValue < 0)
208         return false;
209       return true;
210     };
211     if (isa<FixedVectorType>(ConstOff->getType())) {
212       for (unsigned i = 0; i < TargetElemCount; i++) {
213         if (!CheckValueSize(ConstOff->getAggregateElement(i)))
214           return false;
215       }
216     } else {
217       if (!CheckValueSize(ConstOff))
218         return false;
219     }
220   }
221   return true;
222 }
223 
224 Value *MVEGatherScatterLowering::decomposePtr(Value *Ptr, Value *&Offsets,
225                                               int &Scale, FixedVectorType *Ty,
226                                               Type *MemoryTy,
227                                               IRBuilder<> &Builder) {
228   if (auto *GEP = dyn_cast<GetElementPtrInst>(Ptr)) {
229     if (Value *V = decomposeGEP(Offsets, Ty, GEP, Builder)) {
230       Scale =
231           computeScale(GEP->getSourceElementType()->getPrimitiveSizeInBits(),
232                        MemoryTy->getScalarSizeInBits());
233       return Scale == -1 ? nullptr : V;
234     }
235   }
236 
237   // If we couldn't use the GEP (or it doesn't exist), attempt to use a
238   // BasePtr of 0 with Ptr as the Offsets, so long as there are only 4
239   // elements.
240   FixedVectorType *PtrTy = cast<FixedVectorType>(Ptr->getType());
241   if (PtrTy->getNumElements() != 4 || MemoryTy->getScalarSizeInBits() == 32)
242     return nullptr;
243   Value *Zero = ConstantInt::get(Builder.getInt32Ty(), 0);
244   Value *BasePtr = Builder.CreateIntToPtr(Zero, Builder.getInt8PtrTy());
245   Offsets = Builder.CreatePtrToInt(
246       Ptr, FixedVectorType::get(Builder.getInt32Ty(), 4));
247   Scale = 0;
248   return BasePtr;
249 }
250 
251 Value *MVEGatherScatterLowering::decomposeGEP(Value *&Offsets,
252                                               FixedVectorType *Ty,
253                                               GetElementPtrInst *GEP,
254                                               IRBuilder<> &Builder) {
255   if (!GEP) {
256     LLVM_DEBUG(dbgs() << "masked gathers/scatters: no getelementpointer "
257                       << "found\n");
258     return nullptr;
259   }
260   LLVM_DEBUG(dbgs() << "masked gathers/scatters: getelementpointer found."
261                     << " Looking at intrinsic for base + vector of offsets\n");
262   Value *GEPPtr = GEP->getPointerOperand();
263   Offsets = GEP->getOperand(1);
264   if (GEPPtr->getType()->isVectorTy() ||
265       !isa<FixedVectorType>(Offsets->getType()))
266     return nullptr;
267 
268   if (GEP->getNumOperands() != 2) {
269     LLVM_DEBUG(dbgs() << "masked gathers/scatters: getelementptr with too many"
270                       << " operands. Expanding.\n");
271     return nullptr;
272   }
273   Offsets = GEP->getOperand(1);
274   unsigned OffsetsElemCount =
275       cast<FixedVectorType>(Offsets->getType())->getNumElements();
276   // Paranoid check whether the number of parallel lanes is the same
277   assert(Ty->getNumElements() == OffsetsElemCount);
278 
279   ZExtInst *ZextOffs = dyn_cast<ZExtInst>(Offsets);
280   if (ZextOffs)
281     Offsets = ZextOffs->getOperand(0);
282   FixedVectorType *OffsetType = cast<FixedVectorType>(Offsets->getType());
283 
284   // If the offsets are already being zext-ed to <N x i32>, that relieves us of
285   // having to make sure that they won't overflow.
286   if (!ZextOffs || cast<FixedVectorType>(ZextOffs->getDestTy())
287                            ->getElementType()
288                            ->getScalarSizeInBits() != 32)
289     if (!checkOffsetSize(Offsets, OffsetsElemCount))
290       return nullptr;
291 
292   // The offset sizes have been checked; if any truncating or zext-ing is
293   // required to fix them, do that now
294   if (Ty != Offsets->getType()) {
295     if ((Ty->getElementType()->getScalarSizeInBits() <
296          OffsetType->getElementType()->getScalarSizeInBits())) {
297       Offsets = Builder.CreateTrunc(Offsets, Ty);
298     } else {
299       Offsets = Builder.CreateZExt(Offsets, VectorType::getInteger(Ty));
300     }
301   }
302   // If none of the checks failed, return the gep's base pointer
303   LLVM_DEBUG(dbgs() << "masked gathers/scatters: found correct offsets\n");
304   return GEPPtr;
305 }
306 
307 void MVEGatherScatterLowering::lookThroughBitcast(Value *&Ptr) {
308   // Look through bitcast instruction if #elements is the same
309   if (auto *BitCast = dyn_cast<BitCastInst>(Ptr)) {
310     auto *BCTy = cast<FixedVectorType>(BitCast->getType());
311     auto *BCSrcTy = cast<FixedVectorType>(BitCast->getOperand(0)->getType());
312     if (BCTy->getNumElements() == BCSrcTy->getNumElements()) {
313       LLVM_DEBUG(dbgs() << "masked gathers/scatters: looking through "
314                         << "bitcast\n");
315       Ptr = BitCast->getOperand(0);
316     }
317   }
318 }
319 
320 int MVEGatherScatterLowering::computeScale(unsigned GEPElemSize,
321                                            unsigned MemoryElemSize) {
322   // This can be a 32bit load/store scaled by 4, a 16bit load/store scaled by 2,
323   // or a 8bit, 16bit or 32bit load/store scaled by 1
324   if (GEPElemSize == 32 && MemoryElemSize == 32)
325     return 2;
326   else if (GEPElemSize == 16 && MemoryElemSize == 16)
327     return 1;
328   else if (GEPElemSize == 8)
329     return 0;
330   LLVM_DEBUG(dbgs() << "masked gathers/scatters: incorrect scale. Can't "
331                     << "create intrinsic\n");
332   return -1;
333 }
334 
335 Optional<int64_t> MVEGatherScatterLowering::getIfConst(const Value *V) {
336   const Constant *C = dyn_cast<Constant>(V);
337   if (C != nullptr)
338     return Optional<int64_t>{C->getUniqueInteger().getSExtValue()};
339   if (!isa<Instruction>(V))
340     return Optional<int64_t>{};
341 
342   const Instruction *I = cast<Instruction>(V);
343   if (I->getOpcode() == Instruction::Add ||
344               I->getOpcode() == Instruction::Mul) {
345     Optional<int64_t> Op0 = getIfConst(I->getOperand(0));
346     Optional<int64_t> Op1 = getIfConst(I->getOperand(1));
347     if (!Op0 || !Op1)
348       return Optional<int64_t>{};
349     if (I->getOpcode() == Instruction::Add)
350       return Optional<int64_t>{Op0.getValue() + Op1.getValue()};
351     if (I->getOpcode() == Instruction::Mul)
352       return Optional<int64_t>{Op0.getValue() * Op1.getValue()};
353   }
354   return Optional<int64_t>{};
355 }
356 
357 std::pair<Value *, int64_t>
358 MVEGatherScatterLowering::getVarAndConst(Value *Inst, int TypeScale) {
359   std::pair<Value *, int64_t> ReturnFalse =
360       std::pair<Value *, int64_t>(nullptr, 0);
361   // At this point, the instruction we're looking at must be an add or we
362   // bail out
363   Instruction *Add = dyn_cast<Instruction>(Inst);
364   if (Add == nullptr || Add->getOpcode() != Instruction::Add)
365     return ReturnFalse;
366 
367   Value *Summand;
368   Optional<int64_t> Const;
369   // Find out which operand the value that is increased is
370   if ((Const = getIfConst(Add->getOperand(0))))
371     Summand = Add->getOperand(1);
372   else if ((Const = getIfConst(Add->getOperand(1))))
373     Summand = Add->getOperand(0);
374   else
375     return ReturnFalse;
376 
377   // Check that the constant is small enough for an incrementing gather
378   int64_t Immediate = Const.getValue() << TypeScale;
379   if (Immediate > 512 || Immediate < -512 || Immediate % 4 != 0)
380     return ReturnFalse;
381 
382   return std::pair<Value *, int64_t>(Summand, Immediate);
383 }
384 
385 Instruction *MVEGatherScatterLowering::lowerGather(IntrinsicInst *I) {
386   using namespace PatternMatch;
387   LLVM_DEBUG(dbgs() << "masked gathers: checking transform preconditions\n"
388                     << *I << "\n");
389 
390   // @llvm.masked.gather.*(Ptrs, alignment, Mask, Src0)
391   // Attempt to turn the masked gather in I into a MVE intrinsic
392   // Potentially optimising the addressing modes as we do so.
393   auto *Ty = cast<FixedVectorType>(I->getType());
394   Value *Ptr = I->getArgOperand(0);
395   Align Alignment = cast<ConstantInt>(I->getArgOperand(1))->getAlignValue();
396   Value *Mask = I->getArgOperand(2);
397   Value *PassThru = I->getArgOperand(3);
398 
399   if (!isLegalTypeAndAlignment(Ty->getNumElements(), Ty->getScalarSizeInBits(),
400                                Alignment))
401     return nullptr;
402   lookThroughBitcast(Ptr);
403   assert(Ptr->getType()->isVectorTy() && "Unexpected pointer type");
404 
405   IRBuilder<> Builder(I->getContext());
406   Builder.SetInsertPoint(I);
407   Builder.SetCurrentDebugLocation(I->getDebugLoc());
408 
409   Instruction *Root = I;
410 
411   Instruction *Load = tryCreateIncrementingGatScat(I, Ptr, Builder);
412   if (!Load)
413     Load = tryCreateMaskedGatherOffset(I, Ptr, Root, Builder);
414   if (!Load)
415     Load = tryCreateMaskedGatherBase(I, Ptr, Builder);
416   if (!Load)
417     return nullptr;
418 
419   if (!isa<UndefValue>(PassThru) && !match(PassThru, m_Zero())) {
420     LLVM_DEBUG(dbgs() << "masked gathers: found non-trivial passthru - "
421                       << "creating select\n");
422     Load = SelectInst::Create(Mask, Load, PassThru);
423     Builder.Insert(Load);
424   }
425 
426   Root->replaceAllUsesWith(Load);
427   Root->eraseFromParent();
428   if (Root != I)
429     // If this was an extending gather, we need to get rid of the sext/zext
430     // sext/zext as well as of the gather itself
431     I->eraseFromParent();
432 
433   LLVM_DEBUG(dbgs() << "masked gathers: successfully built masked gather\n"
434                     << *Load << "\n");
435   return Load;
436 }
437 
438 Instruction *MVEGatherScatterLowering::tryCreateMaskedGatherBase(
439     IntrinsicInst *I, Value *Ptr, IRBuilder<> &Builder, int64_t Increment) {
440   using namespace PatternMatch;
441   auto *Ty = cast<FixedVectorType>(I->getType());
442   LLVM_DEBUG(dbgs() << "masked gathers: loading from vector of pointers\n");
443   if (Ty->getNumElements() != 4 || Ty->getScalarSizeInBits() != 32)
444     // Can't build an intrinsic for this
445     return nullptr;
446   Value *Mask = I->getArgOperand(2);
447   if (match(Mask, m_One()))
448     return Builder.CreateIntrinsic(Intrinsic::arm_mve_vldr_gather_base,
449                                    {Ty, Ptr->getType()},
450                                    {Ptr, Builder.getInt32(Increment)});
451   else
452     return Builder.CreateIntrinsic(
453         Intrinsic::arm_mve_vldr_gather_base_predicated,
454         {Ty, Ptr->getType(), Mask->getType()},
455         {Ptr, Builder.getInt32(Increment), Mask});
456 }
457 
458 Instruction *MVEGatherScatterLowering::tryCreateMaskedGatherBaseWB(
459     IntrinsicInst *I, Value *Ptr, IRBuilder<> &Builder, int64_t Increment) {
460   using namespace PatternMatch;
461   auto *Ty = cast<FixedVectorType>(I->getType());
462   LLVM_DEBUG(dbgs() << "masked gathers: loading from vector of pointers with "
463                     << "writeback\n");
464   if (Ty->getNumElements() != 4 || Ty->getScalarSizeInBits() != 32)
465     // Can't build an intrinsic for this
466     return nullptr;
467   Value *Mask = I->getArgOperand(2);
468   if (match(Mask, m_One()))
469     return Builder.CreateIntrinsic(Intrinsic::arm_mve_vldr_gather_base_wb,
470                                    {Ty, Ptr->getType()},
471                                    {Ptr, Builder.getInt32(Increment)});
472   else
473     return Builder.CreateIntrinsic(
474         Intrinsic::arm_mve_vldr_gather_base_wb_predicated,
475         {Ty, Ptr->getType(), Mask->getType()},
476         {Ptr, Builder.getInt32(Increment), Mask});
477 }
478 
479 Instruction *MVEGatherScatterLowering::tryCreateMaskedGatherOffset(
480     IntrinsicInst *I, Value *Ptr, Instruction *&Root, IRBuilder<> &Builder) {
481   using namespace PatternMatch;
482 
483   Type *MemoryTy = I->getType();
484   Type *ResultTy = MemoryTy;
485 
486   unsigned Unsigned = 1;
487   // The size of the gather was already checked in isLegalTypeAndAlignment;
488   // if it was not a full vector width an appropriate extend should follow.
489   auto *Extend = Root;
490   if (MemoryTy->getPrimitiveSizeInBits() < 128) {
491     // Only transform gathers with exactly one use
492     if (!I->hasOneUse())
493       return nullptr;
494 
495     // The correct root to replace is not the CallInst itself, but the
496     // instruction which extends it
497     Extend = cast<Instruction>(*I->users().begin());
498     if (isa<SExtInst>(Extend)) {
499       Unsigned = 0;
500     } else if (!isa<ZExtInst>(Extend)) {
501       LLVM_DEBUG(dbgs() << "masked gathers: extend needed but not provided. "
502                         << "Expanding\n");
503       return nullptr;
504     }
505     LLVM_DEBUG(dbgs() << "masked gathers: found an extending gather\n");
506     ResultTy = Extend->getType();
507     // The final size of the gather must be a full vector width
508     if (ResultTy->getPrimitiveSizeInBits() != 128) {
509       LLVM_DEBUG(dbgs() << "masked gathers: extending from the wrong type. "
510                         << "Expanding\n");
511       return nullptr;
512     }
513   }
514 
515   Value *Offsets;
516   int Scale;
517   Value *BasePtr = decomposePtr(
518       Ptr, Offsets, Scale, cast<FixedVectorType>(ResultTy), MemoryTy, Builder);
519   if (!BasePtr)
520     return nullptr;
521 
522   Root = Extend;
523   Value *Mask = I->getArgOperand(2);
524   if (!match(Mask, m_One()))
525     return Builder.CreateIntrinsic(
526         Intrinsic::arm_mve_vldr_gather_offset_predicated,
527         {ResultTy, BasePtr->getType(), Offsets->getType(), Mask->getType()},
528         {BasePtr, Offsets, Builder.getInt32(MemoryTy->getScalarSizeInBits()),
529          Builder.getInt32(Scale), Builder.getInt32(Unsigned), Mask});
530   else
531     return Builder.CreateIntrinsic(
532         Intrinsic::arm_mve_vldr_gather_offset,
533         {ResultTy, BasePtr->getType(), Offsets->getType()},
534         {BasePtr, Offsets, Builder.getInt32(MemoryTy->getScalarSizeInBits()),
535          Builder.getInt32(Scale), Builder.getInt32(Unsigned)});
536 }
537 
538 Instruction *MVEGatherScatterLowering::lowerScatter(IntrinsicInst *I) {
539   using namespace PatternMatch;
540   LLVM_DEBUG(dbgs() << "masked scatters: checking transform preconditions\n"
541                     << *I << "\n");
542 
543   // @llvm.masked.scatter.*(data, ptrs, alignment, mask)
544   // Attempt to turn the masked scatter in I into a MVE intrinsic
545   // Potentially optimising the addressing modes as we do so.
546   Value *Input = I->getArgOperand(0);
547   Value *Ptr = I->getArgOperand(1);
548   Align Alignment = cast<ConstantInt>(I->getArgOperand(2))->getAlignValue();
549   auto *Ty = cast<FixedVectorType>(Input->getType());
550 
551   if (!isLegalTypeAndAlignment(Ty->getNumElements(), Ty->getScalarSizeInBits(),
552                                Alignment))
553     return nullptr;
554 
555   lookThroughBitcast(Ptr);
556   assert(Ptr->getType()->isVectorTy() && "Unexpected pointer type");
557 
558   IRBuilder<> Builder(I->getContext());
559   Builder.SetInsertPoint(I);
560   Builder.SetCurrentDebugLocation(I->getDebugLoc());
561 
562   Instruction *Store = tryCreateIncrementingGatScat(I, Ptr, Builder);
563   if (!Store)
564     Store = tryCreateMaskedScatterOffset(I, Ptr, Builder);
565   if (!Store)
566     Store = tryCreateMaskedScatterBase(I, Ptr, Builder);
567   if (!Store)
568     return nullptr;
569 
570   LLVM_DEBUG(dbgs() << "masked scatters: successfully built masked scatter\n"
571                     << *Store << "\n");
572   I->eraseFromParent();
573   return Store;
574 }
575 
576 Instruction *MVEGatherScatterLowering::tryCreateMaskedScatterBase(
577     IntrinsicInst *I, Value *Ptr, IRBuilder<> &Builder, int64_t Increment) {
578   using namespace PatternMatch;
579   Value *Input = I->getArgOperand(0);
580   auto *Ty = cast<FixedVectorType>(Input->getType());
581   // Only QR variants allow truncating
582   if (!(Ty->getNumElements() == 4 && Ty->getScalarSizeInBits() == 32)) {
583     // Can't build an intrinsic for this
584     return nullptr;
585   }
586   Value *Mask = I->getArgOperand(3);
587   //  int_arm_mve_vstr_scatter_base(_predicated) addr, offset, data(, mask)
588   LLVM_DEBUG(dbgs() << "masked scatters: storing to a vector of pointers\n");
589   if (match(Mask, m_One()))
590     return Builder.CreateIntrinsic(Intrinsic::arm_mve_vstr_scatter_base,
591                                    {Ptr->getType(), Input->getType()},
592                                    {Ptr, Builder.getInt32(Increment), Input});
593   else
594     return Builder.CreateIntrinsic(
595         Intrinsic::arm_mve_vstr_scatter_base_predicated,
596         {Ptr->getType(), Input->getType(), Mask->getType()},
597         {Ptr, Builder.getInt32(Increment), Input, Mask});
598 }
599 
600 Instruction *MVEGatherScatterLowering::tryCreateMaskedScatterBaseWB(
601     IntrinsicInst *I, Value *Ptr, IRBuilder<> &Builder, int64_t Increment) {
602   using namespace PatternMatch;
603   Value *Input = I->getArgOperand(0);
604   auto *Ty = cast<FixedVectorType>(Input->getType());
605   LLVM_DEBUG(dbgs() << "masked scatters: storing to a vector of pointers "
606                     << "with writeback\n");
607   if (Ty->getNumElements() != 4 || Ty->getScalarSizeInBits() != 32)
608     // Can't build an intrinsic for this
609     return nullptr;
610   Value *Mask = I->getArgOperand(3);
611   if (match(Mask, m_One()))
612     return Builder.CreateIntrinsic(Intrinsic::arm_mve_vstr_scatter_base_wb,
613                                    {Ptr->getType(), Input->getType()},
614                                    {Ptr, Builder.getInt32(Increment), Input});
615   else
616     return Builder.CreateIntrinsic(
617         Intrinsic::arm_mve_vstr_scatter_base_wb_predicated,
618         {Ptr->getType(), Input->getType(), Mask->getType()},
619         {Ptr, Builder.getInt32(Increment), Input, Mask});
620 }
621 
622 Instruction *MVEGatherScatterLowering::tryCreateMaskedScatterOffset(
623     IntrinsicInst *I, Value *Ptr, IRBuilder<> &Builder) {
624   using namespace PatternMatch;
625   Value *Input = I->getArgOperand(0);
626   Value *Mask = I->getArgOperand(3);
627   Type *InputTy = Input->getType();
628   Type *MemoryTy = InputTy;
629 
630   LLVM_DEBUG(dbgs() << "masked scatters: getelementpointer found. Storing"
631                     << " to base + vector of offsets\n");
632   // If the input has been truncated, try to integrate that trunc into the
633   // scatter instruction (we don't care about alignment here)
634   if (TruncInst *Trunc = dyn_cast<TruncInst>(Input)) {
635     Value *PreTrunc = Trunc->getOperand(0);
636     Type *PreTruncTy = PreTrunc->getType();
637     if (PreTruncTy->getPrimitiveSizeInBits() == 128) {
638       Input = PreTrunc;
639       InputTy = PreTruncTy;
640     }
641   }
642   bool ExtendInput = false;
643   if (InputTy->getPrimitiveSizeInBits() < 128 &&
644       InputTy->isIntOrIntVectorTy()) {
645     // If we can't find a trunc to incorporate into the instruction, create an
646     // implicit one with a zext, so that we can still create a scatter. We know
647     // that the input type is 4x/8x/16x and of type i8/i16/i32, so any type
648     // smaller than 128 bits will divide evenly into a 128bit vector.
649     InputTy = InputTy->getWithNewBitWidth(
650         128 / cast<FixedVectorType>(InputTy)->getNumElements());
651     ExtendInput = true;
652     LLVM_DEBUG(dbgs() << "masked scatters: Small input type, will extend:\n"
653                       << *Input << "\n");
654   }
655   if (InputTy->getPrimitiveSizeInBits() != 128) {
656     LLVM_DEBUG(dbgs() << "masked scatters: cannot create scatters for "
657                          "non-standard input types. Expanding.\n");
658     return nullptr;
659   }
660 
661   Value *Offsets;
662   int Scale;
663   Value *BasePtr = decomposePtr(
664       Ptr, Offsets, Scale, cast<FixedVectorType>(InputTy), MemoryTy, Builder);
665   if (!BasePtr)
666     return nullptr;
667 
668   if (ExtendInput)
669     Input = Builder.CreateZExt(Input, InputTy);
670   if (!match(Mask, m_One()))
671     return Builder.CreateIntrinsic(
672         Intrinsic::arm_mve_vstr_scatter_offset_predicated,
673         {BasePtr->getType(), Offsets->getType(), Input->getType(),
674          Mask->getType()},
675         {BasePtr, Offsets, Input,
676          Builder.getInt32(MemoryTy->getScalarSizeInBits()),
677          Builder.getInt32(Scale), Mask});
678   else
679     return Builder.CreateIntrinsic(
680         Intrinsic::arm_mve_vstr_scatter_offset,
681         {BasePtr->getType(), Offsets->getType(), Input->getType()},
682         {BasePtr, Offsets, Input,
683          Builder.getInt32(MemoryTy->getScalarSizeInBits()),
684          Builder.getInt32(Scale)});
685 }
686 
687 Instruction *MVEGatherScatterLowering::tryCreateIncrementingGatScat(
688     IntrinsicInst *I, Value *Ptr, IRBuilder<> &Builder) {
689   FixedVectorType *Ty;
690   if (I->getIntrinsicID() == Intrinsic::masked_gather)
691     Ty = cast<FixedVectorType>(I->getType());
692   else
693     Ty = cast<FixedVectorType>(I->getArgOperand(0)->getType());
694 
695   // Incrementing gathers only exist for v4i32
696   if (Ty->getNumElements() != 4 || Ty->getScalarSizeInBits() != 32)
697     return nullptr;
698   // Incrementing gathers are not beneficial outside of a loop
699   Loop *L = LI->getLoopFor(I->getParent());
700   if (L == nullptr)
701     return nullptr;
702 
703   // Decompose the GEP into Base and Offsets
704   GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(Ptr);
705   Value *Offsets;
706   Value *BasePtr = decomposeGEP(Offsets, Ty, GEP, Builder);
707   if (!BasePtr)
708     return nullptr;
709 
710   LLVM_DEBUG(dbgs() << "masked gathers/scatters: trying to build incrementing "
711                        "wb gather/scatter\n");
712 
713   // The gep was in charge of making sure the offsets are scaled correctly
714   // - calculate that factor so it can be applied by hand
715   DataLayout DT = I->getParent()->getParent()->getParent()->getDataLayout();
716   int TypeScale =
717       computeScale(DT.getTypeSizeInBits(GEP->getOperand(0)->getType()),
718                    DT.getTypeSizeInBits(GEP->getType()) /
719                        cast<FixedVectorType>(GEP->getType())->getNumElements());
720   if (TypeScale == -1)
721     return nullptr;
722 
723   if (GEP->hasOneUse()) {
724     // Only in this case do we want to build a wb gather, because the wb will
725     // change the phi which does affect other users of the gep (which will still
726     // be using the phi in the old way)
727     if (auto *Load = tryCreateIncrementingWBGatScat(I, BasePtr, Offsets,
728                                                     TypeScale, Builder))
729       return Load;
730   }
731 
732   LLVM_DEBUG(dbgs() << "masked gathers/scatters: trying to build incrementing "
733                        "non-wb gather/scatter\n");
734 
735   std::pair<Value *, int64_t> Add = getVarAndConst(Offsets, TypeScale);
736   if (Add.first == nullptr)
737     return nullptr;
738   Value *OffsetsIncoming = Add.first;
739   int64_t Immediate = Add.second;
740 
741   // Make sure the offsets are scaled correctly
742   Instruction *ScaledOffsets = BinaryOperator::Create(
743       Instruction::Shl, OffsetsIncoming,
744       Builder.CreateVectorSplat(Ty->getNumElements(), Builder.getInt32(TypeScale)),
745       "ScaledIndex", I);
746   // Add the base to the offsets
747   OffsetsIncoming = BinaryOperator::Create(
748       Instruction::Add, ScaledOffsets,
749       Builder.CreateVectorSplat(
750           Ty->getNumElements(),
751           Builder.CreatePtrToInt(
752               BasePtr,
753               cast<VectorType>(ScaledOffsets->getType())->getElementType())),
754       "StartIndex", I);
755 
756   if (I->getIntrinsicID() == Intrinsic::masked_gather)
757     return tryCreateMaskedGatherBase(I, OffsetsIncoming, Builder, Immediate);
758   else
759     return tryCreateMaskedScatterBase(I, OffsetsIncoming, Builder, Immediate);
760 }
761 
762 Instruction *MVEGatherScatterLowering::tryCreateIncrementingWBGatScat(
763     IntrinsicInst *I, Value *BasePtr, Value *Offsets, unsigned TypeScale,
764     IRBuilder<> &Builder) {
765   // Check whether this gather's offset is incremented by a constant - if so,
766   // and the load is of the right type, we can merge this into a QI gather
767   Loop *L = LI->getLoopFor(I->getParent());
768   // Offsets that are worth merging into this instruction will be incremented
769   // by a constant, thus we're looking for an add of a phi and a constant
770   PHINode *Phi = dyn_cast<PHINode>(Offsets);
771   if (Phi == nullptr || Phi->getNumIncomingValues() != 2 ||
772       Phi->getParent() != L->getHeader() || Phi->getNumUses() != 2)
773     // No phi means no IV to write back to; if there is a phi, we expect it
774     // to have exactly two incoming values; the only phis we are interested in
775     // will be loop IV's and have exactly two uses, one in their increment and
776     // one in the gather's gep
777     return nullptr;
778 
779   unsigned IncrementIndex =
780       Phi->getIncomingBlock(0) == L->getLoopLatch() ? 0 : 1;
781   // Look through the phi to the phi increment
782   Offsets = Phi->getIncomingValue(IncrementIndex);
783 
784   std::pair<Value *, int64_t> Add = getVarAndConst(Offsets, TypeScale);
785   if (Add.first == nullptr)
786     return nullptr;
787   Value *OffsetsIncoming = Add.first;
788   int64_t Immediate = Add.second;
789   if (OffsetsIncoming != Phi)
790     // Then the increment we are looking at is not an increment of the
791     // induction variable, and we don't want to do a writeback
792     return nullptr;
793 
794   Builder.SetInsertPoint(&Phi->getIncomingBlock(1 - IncrementIndex)->back());
795   unsigned NumElems =
796       cast<FixedVectorType>(OffsetsIncoming->getType())->getNumElements();
797 
798   // Make sure the offsets are scaled correctly
799   Instruction *ScaledOffsets = BinaryOperator::Create(
800       Instruction::Shl, Phi->getIncomingValue(1 - IncrementIndex),
801       Builder.CreateVectorSplat(NumElems, Builder.getInt32(TypeScale)),
802       "ScaledIndex", &Phi->getIncomingBlock(1 - IncrementIndex)->back());
803   // Add the base to the offsets
804   OffsetsIncoming = BinaryOperator::Create(
805       Instruction::Add, ScaledOffsets,
806       Builder.CreateVectorSplat(
807           NumElems,
808           Builder.CreatePtrToInt(
809               BasePtr,
810               cast<VectorType>(ScaledOffsets->getType())->getElementType())),
811       "StartIndex", &Phi->getIncomingBlock(1 - IncrementIndex)->back());
812   // The gather is pre-incrementing
813   OffsetsIncoming = BinaryOperator::Create(
814       Instruction::Sub, OffsetsIncoming,
815       Builder.CreateVectorSplat(NumElems, Builder.getInt32(Immediate)),
816       "PreIncrementStartIndex",
817       &Phi->getIncomingBlock(1 - IncrementIndex)->back());
818   Phi->setIncomingValue(1 - IncrementIndex, OffsetsIncoming);
819 
820   Builder.SetInsertPoint(I);
821 
822   Instruction *EndResult;
823   Instruction *NewInduction;
824   if (I->getIntrinsicID() == Intrinsic::masked_gather) {
825     // Build the incrementing gather
826     Value *Load = tryCreateMaskedGatherBaseWB(I, Phi, Builder, Immediate);
827     // One value to be handed to whoever uses the gather, one is the loop
828     // increment
829     EndResult = ExtractValueInst::Create(Load, 0, "Gather");
830     NewInduction = ExtractValueInst::Create(Load, 1, "GatherIncrement");
831     Builder.Insert(EndResult);
832     Builder.Insert(NewInduction);
833   } else {
834     // Build the incrementing scatter
835     EndResult = NewInduction =
836         tryCreateMaskedScatterBaseWB(I, Phi, Builder, Immediate);
837   }
838   Instruction *AddInst = cast<Instruction>(Offsets);
839   AddInst->replaceAllUsesWith(NewInduction);
840   AddInst->eraseFromParent();
841   Phi->setIncomingValue(IncrementIndex, NewInduction);
842 
843   return EndResult;
844 }
845 
846 void MVEGatherScatterLowering::pushOutAdd(PHINode *&Phi,
847                                           Value *OffsSecondOperand,
848                                           unsigned StartIndex) {
849   LLVM_DEBUG(dbgs() << "masked gathers/scatters: optimising add instruction\n");
850   Instruction *InsertionPoint =
851         &cast<Instruction>(Phi->getIncomingBlock(StartIndex)->back());
852   // Initialize the phi with a vector that contains a sum of the constants
853   Instruction *NewIndex = BinaryOperator::Create(
854       Instruction::Add, Phi->getIncomingValue(StartIndex), OffsSecondOperand,
855       "PushedOutAdd", InsertionPoint);
856   unsigned IncrementIndex = StartIndex == 0 ? 1 : 0;
857 
858   // Order such that start index comes first (this reduces mov's)
859   Phi->addIncoming(NewIndex, Phi->getIncomingBlock(StartIndex));
860   Phi->addIncoming(Phi->getIncomingValue(IncrementIndex),
861                    Phi->getIncomingBlock(IncrementIndex));
862   Phi->removeIncomingValue(IncrementIndex);
863   Phi->removeIncomingValue(StartIndex);
864 }
865 
866 void MVEGatherScatterLowering::pushOutMul(PHINode *&Phi,
867                                           Value *IncrementPerRound,
868                                           Value *OffsSecondOperand,
869                                           unsigned LoopIncrement,
870                                           IRBuilder<> &Builder) {
871   LLVM_DEBUG(dbgs() << "masked gathers/scatters: optimising mul instruction\n");
872 
873   // Create a new scalar add outside of the loop and transform it to a splat
874   // by which loop variable can be incremented
875   Instruction *InsertionPoint = &cast<Instruction>(
876         Phi->getIncomingBlock(LoopIncrement == 1 ? 0 : 1)->back());
877 
878   // Create a new index
879   Value *StartIndex = BinaryOperator::Create(
880       Instruction::Mul, Phi->getIncomingValue(LoopIncrement == 1 ? 0 : 1),
881       OffsSecondOperand, "PushedOutMul", InsertionPoint);
882 
883   Instruction *Product =
884       BinaryOperator::Create(Instruction::Mul, IncrementPerRound,
885                              OffsSecondOperand, "Product", InsertionPoint);
886   // Increment NewIndex by Product instead of the multiplication
887   Instruction *NewIncrement = BinaryOperator::Create(
888       Instruction::Add, Phi, Product, "IncrementPushedOutMul",
889       cast<Instruction>(Phi->getIncomingBlock(LoopIncrement)->back())
890           .getPrevNode());
891 
892   Phi->addIncoming(StartIndex,
893                    Phi->getIncomingBlock(LoopIncrement == 1 ? 0 : 1));
894   Phi->addIncoming(NewIncrement, Phi->getIncomingBlock(LoopIncrement));
895   Phi->removeIncomingValue((unsigned)0);
896   Phi->removeIncomingValue((unsigned)0);
897 }
898 
899 // Check whether all usages of this instruction are as offsets of
900 // gathers/scatters or simple arithmetics only used by gathers/scatters
901 static bool hasAllGatScatUsers(Instruction *I) {
902   if (I->hasNUses(0)) {
903     return false;
904   }
905   bool Gatscat = true;
906   for (User *U : I->users()) {
907     if (!isa<Instruction>(U))
908       return false;
909     if (isa<GetElementPtrInst>(U) ||
910         isGatherScatter(dyn_cast<IntrinsicInst>(U))) {
911       return Gatscat;
912     } else {
913       unsigned OpCode = cast<Instruction>(U)->getOpcode();
914       if ((OpCode == Instruction::Add || OpCode == Instruction::Mul) &&
915           hasAllGatScatUsers(cast<Instruction>(U))) {
916         continue;
917       }
918       return false;
919     }
920   }
921   return Gatscat;
922 }
923 
924 bool MVEGatherScatterLowering::optimiseOffsets(Value *Offsets, BasicBlock *BB,
925                                                LoopInfo *LI) {
926   LLVM_DEBUG(dbgs() << "masked gathers/scatters: trying to optimize\n"
927                     << *Offsets << "\n");
928   // Optimise the addresses of gathers/scatters by moving invariant
929   // calculations out of the loop
930   if (!isa<Instruction>(Offsets))
931     return false;
932   Instruction *Offs = cast<Instruction>(Offsets);
933   if (Offs->getOpcode() != Instruction::Add &&
934       Offs->getOpcode() != Instruction::Mul)
935     return false;
936   Loop *L = LI->getLoopFor(BB);
937   if (L == nullptr)
938     return false;
939   if (!Offs->hasOneUse()) {
940     if (!hasAllGatScatUsers(Offs))
941       return false;
942   }
943 
944   // Find out which, if any, operand of the instruction
945   // is a phi node
946   PHINode *Phi;
947   int OffsSecondOp;
948   if (isa<PHINode>(Offs->getOperand(0))) {
949     Phi = cast<PHINode>(Offs->getOperand(0));
950     OffsSecondOp = 1;
951   } else if (isa<PHINode>(Offs->getOperand(1))) {
952     Phi = cast<PHINode>(Offs->getOperand(1));
953     OffsSecondOp = 0;
954   } else {
955     bool Changed = true;
956     if (isa<Instruction>(Offs->getOperand(0)) &&
957         L->contains(cast<Instruction>(Offs->getOperand(0))))
958       Changed |= optimiseOffsets(Offs->getOperand(0), BB, LI);
959     if (isa<Instruction>(Offs->getOperand(1)) &&
960         L->contains(cast<Instruction>(Offs->getOperand(1))))
961       Changed |= optimiseOffsets(Offs->getOperand(1), BB, LI);
962     if (!Changed) {
963       return false;
964     } else {
965       if (isa<PHINode>(Offs->getOperand(0))) {
966         Phi = cast<PHINode>(Offs->getOperand(0));
967         OffsSecondOp = 1;
968       } else if (isa<PHINode>(Offs->getOperand(1))) {
969         Phi = cast<PHINode>(Offs->getOperand(1));
970         OffsSecondOp = 0;
971       } else {
972         return false;
973       }
974     }
975   }
976   // A phi node we want to perform this function on should be from the
977   // loop header, and shouldn't have more than 2 incoming values
978   if (Phi->getParent() != L->getHeader() ||
979       Phi->getNumIncomingValues() != 2)
980     return false;
981 
982   // The phi must be an induction variable
983   int IncrementingBlock = -1;
984 
985   for (int i = 0; i < 2; i++)
986     if (auto *Op = dyn_cast<Instruction>(Phi->getIncomingValue(i)))
987       if (Op->getOpcode() == Instruction::Add &&
988           (Op->getOperand(0) == Phi || Op->getOperand(1) == Phi))
989         IncrementingBlock = i;
990   if (IncrementingBlock == -1)
991     return false;
992 
993   Instruction *IncInstruction =
994       cast<Instruction>(Phi->getIncomingValue(IncrementingBlock));
995 
996   // If the phi is not used by anything else, we can just adapt it when
997   // replacing the instruction; if it is, we'll have to duplicate it
998   PHINode *NewPhi;
999   Value *IncrementPerRound = IncInstruction->getOperand(
1000       (IncInstruction->getOperand(0) == Phi) ? 1 : 0);
1001 
1002   // Get the value that is added to/multiplied with the phi
1003   Value *OffsSecondOperand = Offs->getOperand(OffsSecondOp);
1004 
1005   if (IncrementPerRound->getType() != OffsSecondOperand->getType() ||
1006       !L->isLoopInvariant(OffsSecondOperand))
1007     // Something has gone wrong, abort
1008     return false;
1009 
1010   // Only proceed if the increment per round is a constant or an instruction
1011   // which does not originate from within the loop
1012   if (!isa<Constant>(IncrementPerRound) &&
1013       !(isa<Instruction>(IncrementPerRound) &&
1014         !L->contains(cast<Instruction>(IncrementPerRound))))
1015     return false;
1016 
1017   if (Phi->getNumUses() == 2) {
1018     // No other users -> reuse existing phi (One user is the instruction
1019     // we're looking at, the other is the phi increment)
1020     if (IncInstruction->getNumUses() != 1) {
1021       // If the incrementing instruction does have more users than
1022       // our phi, we need to copy it
1023       IncInstruction = BinaryOperator::Create(
1024           Instruction::BinaryOps(IncInstruction->getOpcode()), Phi,
1025           IncrementPerRound, "LoopIncrement", IncInstruction);
1026       Phi->setIncomingValue(IncrementingBlock, IncInstruction);
1027     }
1028     NewPhi = Phi;
1029   } else {
1030     // There are other users -> create a new phi
1031     NewPhi = PHINode::Create(Phi->getType(), 0, "NewPhi", Phi);
1032     std::vector<Value *> Increases;
1033     // Copy the incoming values of the old phi
1034     NewPhi->addIncoming(Phi->getIncomingValue(IncrementingBlock == 1 ? 0 : 1),
1035                         Phi->getIncomingBlock(IncrementingBlock == 1 ? 0 : 1));
1036     IncInstruction = BinaryOperator::Create(
1037         Instruction::BinaryOps(IncInstruction->getOpcode()), NewPhi,
1038         IncrementPerRound, "LoopIncrement", IncInstruction);
1039     NewPhi->addIncoming(IncInstruction,
1040                         Phi->getIncomingBlock(IncrementingBlock));
1041     IncrementingBlock = 1;
1042   }
1043 
1044   IRBuilder<> Builder(BB->getContext());
1045   Builder.SetInsertPoint(Phi);
1046   Builder.SetCurrentDebugLocation(Offs->getDebugLoc());
1047 
1048   switch (Offs->getOpcode()) {
1049   case Instruction::Add:
1050     pushOutAdd(NewPhi, OffsSecondOperand, IncrementingBlock == 1 ? 0 : 1);
1051     break;
1052   case Instruction::Mul:
1053     pushOutMul(NewPhi, IncrementPerRound, OffsSecondOperand, IncrementingBlock,
1054                Builder);
1055     break;
1056   default:
1057     return false;
1058   }
1059   LLVM_DEBUG(dbgs() << "masked gathers/scatters: simplified loop variable "
1060                     << "add/mul\n");
1061 
1062   // The instruction has now been "absorbed" into the phi value
1063   Offs->replaceAllUsesWith(NewPhi);
1064   if (Offs->hasNUses(0))
1065     Offs->eraseFromParent();
1066   // Clean up the old increment in case it's unused because we built a new
1067   // one
1068   if (IncInstruction->hasNUses(0))
1069     IncInstruction->eraseFromParent();
1070 
1071   return true;
1072 }
1073 
1074 static Value *CheckAndCreateOffsetAdd(Value *X, Value *Y, Value *GEP,
1075                                       IRBuilder<> &Builder) {
1076   // Splat the non-vector value to a vector of the given type - if the value is
1077   // a constant (and its value isn't too big), we can even use this opportunity
1078   // to scale it to the size of the vector elements
1079   auto FixSummands = [&Builder](FixedVectorType *&VT, Value *&NonVectorVal) {
1080     ConstantInt *Const;
1081     if ((Const = dyn_cast<ConstantInt>(NonVectorVal)) &&
1082         VT->getElementType() != NonVectorVal->getType()) {
1083       unsigned TargetElemSize = VT->getElementType()->getPrimitiveSizeInBits();
1084       uint64_t N = Const->getZExtValue();
1085       if (N < (unsigned)(1 << (TargetElemSize - 1))) {
1086         NonVectorVal = Builder.CreateVectorSplat(
1087             VT->getNumElements(), Builder.getIntN(TargetElemSize, N));
1088         return;
1089       }
1090     }
1091     NonVectorVal =
1092         Builder.CreateVectorSplat(VT->getNumElements(), NonVectorVal);
1093   };
1094 
1095   FixedVectorType *XElType = dyn_cast<FixedVectorType>(X->getType());
1096   FixedVectorType *YElType = dyn_cast<FixedVectorType>(Y->getType());
1097   // If one of X, Y is not a vector, we have to splat it in order
1098   // to add the two of them.
1099   if (XElType && !YElType) {
1100     FixSummands(XElType, Y);
1101     YElType = cast<FixedVectorType>(Y->getType());
1102   } else if (YElType && !XElType) {
1103     FixSummands(YElType, X);
1104     XElType = cast<FixedVectorType>(X->getType());
1105   }
1106   assert(XElType && YElType && "Unknown vector types");
1107   // Check that the summands are of compatible types
1108   if (XElType != YElType) {
1109     LLVM_DEBUG(dbgs() << "masked gathers/scatters: incompatible gep offsets\n");
1110     return nullptr;
1111   }
1112 
1113   if (XElType->getElementType()->getScalarSizeInBits() != 32) {
1114     // Check that by adding the vectors we do not accidentally
1115     // create an overflow
1116     Constant *ConstX = dyn_cast<Constant>(X);
1117     Constant *ConstY = dyn_cast<Constant>(Y);
1118     if (!ConstX || !ConstY)
1119       return nullptr;
1120     unsigned TargetElemSize = 128 / XElType->getNumElements();
1121     for (unsigned i = 0; i < XElType->getNumElements(); i++) {
1122       ConstantInt *ConstXEl =
1123           dyn_cast<ConstantInt>(ConstX->getAggregateElement(i));
1124       ConstantInt *ConstYEl =
1125           dyn_cast<ConstantInt>(ConstY->getAggregateElement(i));
1126       if (!ConstXEl || !ConstYEl ||
1127           ConstXEl->getZExtValue() + ConstYEl->getZExtValue() >=
1128               (unsigned)(1 << (TargetElemSize - 1)))
1129         return nullptr;
1130     }
1131   }
1132 
1133   Value *Add = Builder.CreateAdd(X, Y);
1134 
1135   FixedVectorType *GEPType = cast<FixedVectorType>(GEP->getType());
1136   if (checkOffsetSize(Add, GEPType->getNumElements()))
1137     return Add;
1138   else
1139     return nullptr;
1140 }
1141 
1142 Value *MVEGatherScatterLowering::foldGEP(GetElementPtrInst *GEP,
1143                                          Value *&Offsets,
1144                                          IRBuilder<> &Builder) {
1145   Value *GEPPtr = GEP->getPointerOperand();
1146   Offsets = GEP->getOperand(1);
1147   // We only merge geps with constant offsets, because only for those
1148   // we can make sure that we do not cause an overflow
1149   if (!isa<Constant>(Offsets))
1150     return nullptr;
1151   GetElementPtrInst *BaseGEP;
1152   if ((BaseGEP = dyn_cast<GetElementPtrInst>(GEPPtr))) {
1153     // Merge the two geps into one
1154     Value *BaseBasePtr = foldGEP(BaseGEP, Offsets, Builder);
1155     if (!BaseBasePtr)
1156       return nullptr;
1157     Offsets =
1158         CheckAndCreateOffsetAdd(Offsets, GEP->getOperand(1), GEP, Builder);
1159     if (Offsets == nullptr)
1160       return nullptr;
1161     return BaseBasePtr;
1162   }
1163   return GEPPtr;
1164 }
1165 
1166 bool MVEGatherScatterLowering::optimiseAddress(Value *Address, BasicBlock *BB,
1167                                                LoopInfo *LI) {
1168   GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(Address);
1169   if (!GEP)
1170     return false;
1171   bool Changed = false;
1172   if (GEP->hasOneUse() &&
1173       dyn_cast<GetElementPtrInst>(GEP->getPointerOperand())) {
1174     IRBuilder<> Builder(GEP->getContext());
1175     Builder.SetInsertPoint(GEP);
1176     Builder.SetCurrentDebugLocation(GEP->getDebugLoc());
1177     Value *Offsets;
1178     Value *Base = foldGEP(GEP, Offsets, Builder);
1179     // We only want to merge the geps if there is a real chance that they can be
1180     // used by an MVE gather; thus the offset has to have the correct size
1181     // (always i32 if it is not of vector type) and the base has to be a
1182     // pointer.
1183     if (Offsets && Base && Base != GEP) {
1184       GetElementPtrInst *NewAddress = GetElementPtrInst::Create(
1185           GEP->getSourceElementType(), Base, Offsets, "gep.merged", GEP);
1186       GEP->replaceAllUsesWith(NewAddress);
1187       GEP = NewAddress;
1188       Changed = true;
1189     }
1190   }
1191   Changed |= optimiseOffsets(GEP->getOperand(1), GEP->getParent(), LI);
1192   return Changed;
1193 }
1194 
1195 bool MVEGatherScatterLowering::runOnFunction(Function &F) {
1196   if (!EnableMaskedGatherScatters)
1197     return false;
1198   auto &TPC = getAnalysis<TargetPassConfig>();
1199   auto &TM = TPC.getTM<TargetMachine>();
1200   auto *ST = &TM.getSubtarget<ARMSubtarget>(F);
1201   if (!ST->hasMVEIntegerOps())
1202     return false;
1203   LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
1204   SmallVector<IntrinsicInst *, 4> Gathers;
1205   SmallVector<IntrinsicInst *, 4> Scatters;
1206 
1207   bool Changed = false;
1208 
1209   for (BasicBlock &BB : F) {
1210     Changed |= SimplifyInstructionsInBlock(&BB);
1211 
1212     for (Instruction &I : BB) {
1213       IntrinsicInst *II = dyn_cast<IntrinsicInst>(&I);
1214       if (II && II->getIntrinsicID() == Intrinsic::masked_gather &&
1215           isa<FixedVectorType>(II->getType())) {
1216         Gathers.push_back(II);
1217         Changed |= optimiseAddress(II->getArgOperand(0), II->getParent(), LI);
1218       } else if (II && II->getIntrinsicID() == Intrinsic::masked_scatter &&
1219                  isa<FixedVectorType>(II->getArgOperand(0)->getType())) {
1220         Scatters.push_back(II);
1221         Changed |= optimiseAddress(II->getArgOperand(1), II->getParent(), LI);
1222       }
1223     }
1224   }
1225   for (unsigned i = 0; i < Gathers.size(); i++) {
1226     IntrinsicInst *I = Gathers[i];
1227     Instruction *L = lowerGather(I);
1228     if (L == nullptr)
1229       continue;
1230 
1231     // Get rid of any now dead instructions
1232     SimplifyInstructionsInBlock(L->getParent());
1233     Changed = true;
1234   }
1235 
1236   for (unsigned i = 0; i < Scatters.size(); i++) {
1237     IntrinsicInst *I = Scatters[i];
1238     Instruction *S = lowerScatter(I);
1239     if (S == nullptr)
1240       continue;
1241 
1242     // Get rid of any now dead instructions
1243     SimplifyInstructionsInBlock(S->getParent());
1244     Changed = true;
1245   }
1246   return Changed;
1247 }
1248