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