1 //===- X86InterleavedAccess.cpp -------------------------------------------===//
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 /// \file
10 /// This file contains the X86 implementation of the interleaved accesses
11 /// optimization generating X86-specific instructions/intrinsics for
12 /// interleaved access groups.
13 //
14 //===----------------------------------------------------------------------===//
15 
16 #include "X86ISelLowering.h"
17 #include "X86Subtarget.h"
18 #include "llvm/ADT/ArrayRef.h"
19 #include "llvm/ADT/SmallVector.h"
20 #include "llvm/Analysis/VectorUtils.h"
21 #include "llvm/IR/Constants.h"
22 #include "llvm/IR/DataLayout.h"
23 #include "llvm/IR/DerivedTypes.h"
24 #include "llvm/IR/IRBuilder.h"
25 #include "llvm/IR/Instruction.h"
26 #include "llvm/IR/Instructions.h"
27 #include "llvm/IR/Module.h"
28 #include "llvm/IR/Type.h"
29 #include "llvm/IR/Value.h"
30 #include "llvm/Support/Casting.h"
31 #include "llvm/Support/MachineValueType.h"
32 #include <algorithm>
33 #include <cassert>
34 #include <cmath>
35 #include <cstdint>
36 
37 using namespace llvm;
38 
39 namespace {
40 
41 /// This class holds necessary information to represent an interleaved
42 /// access group and supports utilities to lower the group into
43 /// X86-specific instructions/intrinsics.
44 ///  E.g. A group of interleaving access loads (Factor = 2; accessing every
45 ///       other element)
46 ///        %wide.vec = load <8 x i32>, <8 x i32>* %ptr
47 ///        %v0 = shuffle <8 x i32> %wide.vec, <8 x i32> undef, <0, 2, 4, 6>
48 ///        %v1 = shuffle <8 x i32> %wide.vec, <8 x i32> undef, <1, 3, 5, 7>
49 class X86InterleavedAccessGroup {
50   /// Reference to the wide-load instruction of an interleaved access
51   /// group.
52   Instruction *const Inst;
53 
54   /// Reference to the shuffle(s), consumer(s) of the (load) 'Inst'.
55   ArrayRef<ShuffleVectorInst *> Shuffles;
56 
57   /// Reference to the starting index of each user-shuffle.
58   ArrayRef<unsigned> Indices;
59 
60   /// Reference to the interleaving stride in terms of elements.
61   const unsigned Factor;
62 
63   /// Reference to the underlying target.
64   const X86Subtarget &Subtarget;
65 
66   const DataLayout &DL;
67 
68   IRBuilder<> &Builder;
69 
70   /// Breaks down a vector \p 'Inst' of N elements into \p NumSubVectors
71   /// sub vectors of type \p T. Returns the sub-vectors in \p DecomposedVectors.
72   void decompose(Instruction *Inst, unsigned NumSubVectors, VectorType *T,
73                  SmallVectorImpl<Instruction *> &DecomposedVectors);
74 
75   /// Performs matrix transposition on a 4x4 matrix \p InputVectors and
76   /// returns the transposed-vectors in \p TransposedVectors.
77   /// E.g.
78   /// InputVectors:
79   ///   In-V0 = p1, p2, p3, p4
80   ///   In-V1 = q1, q2, q3, q4
81   ///   In-V2 = r1, r2, r3, r4
82   ///   In-V3 = s1, s2, s3, s4
83   /// OutputVectors:
84   ///   Out-V0 = p1, q1, r1, s1
85   ///   Out-V1 = p2, q2, r2, s2
86   ///   Out-V2 = p3, q3, r3, s3
87   ///   Out-V3 = P4, q4, r4, s4
88   void transpose_4x4(ArrayRef<Instruction *> InputVectors,
89                      SmallVectorImpl<Value *> &TransposedMatrix);
90   void interleave8bitStride4(ArrayRef<Instruction *> InputVectors,
91                              SmallVectorImpl<Value *> &TransposedMatrix,
92                              unsigned NumSubVecElems);
93   void interleave8bitStride4VF8(ArrayRef<Instruction *> InputVectors,
94                                 SmallVectorImpl<Value *> &TransposedMatrix);
95   void interleave8bitStride3(ArrayRef<Instruction *> InputVectors,
96                              SmallVectorImpl<Value *> &TransposedMatrix,
97                              unsigned NumSubVecElems);
98   void deinterleave8bitStride3(ArrayRef<Instruction *> InputVectors,
99                                SmallVectorImpl<Value *> &TransposedMatrix,
100                                unsigned NumSubVecElems);
101 
102 public:
103   /// In order to form an interleaved access group X86InterleavedAccessGroup
104   /// requires a wide-load instruction \p 'I', a group of interleaved-vectors
105   /// \p Shuffs, reference to the first indices of each interleaved-vector
106   /// \p 'Ind' and the interleaving stride factor \p F. In order to generate
107   /// X86-specific instructions/intrinsics it also requires the underlying
108   /// target information \p STarget.
109   explicit X86InterleavedAccessGroup(Instruction *I,
110                                      ArrayRef<ShuffleVectorInst *> Shuffs,
111                                      ArrayRef<unsigned> Ind, const unsigned F,
112                                      const X86Subtarget &STarget,
113                                      IRBuilder<> &B)
114       : Inst(I), Shuffles(Shuffs), Indices(Ind), Factor(F), Subtarget(STarget),
115         DL(Inst->getModule()->getDataLayout()), Builder(B) {}
116 
117   /// Returns true if this interleaved access group can be lowered into
118   /// x86-specific instructions/intrinsics, false otherwise.
119   bool isSupported() const;
120 
121   /// Lowers this interleaved access group into X86-specific
122   /// instructions/intrinsics.
123   bool lowerIntoOptimizedSequence();
124 };
125 
126 } // end anonymous namespace
127 
128 bool X86InterleavedAccessGroup::isSupported() const {
129   VectorType *ShuffleVecTy = Shuffles[0]->getType();
130   Type *ShuffleEltTy = ShuffleVecTy->getVectorElementType();
131   unsigned ShuffleElemSize = DL.getTypeSizeInBits(ShuffleEltTy);
132   unsigned WideInstSize;
133 
134   // Currently, lowering is supported for the following vectors:
135   // Stride 4:
136   //    1. Store and load of 4-element vectors of 64 bits on AVX.
137   //    2. Store of 16/32-element vectors of 8 bits on AVX.
138   // Stride 3:
139   //    1. Load of 16/32-element vectors of 8 bits on AVX.
140   if (!Subtarget.hasAVX() || (Factor != 4 && Factor != 3))
141     return false;
142 
143   if (isa<LoadInst>(Inst)) {
144     WideInstSize = DL.getTypeSizeInBits(Inst->getType());
145     if (cast<LoadInst>(Inst)->getPointerAddressSpace())
146       return false;
147   } else
148     WideInstSize = DL.getTypeSizeInBits(Shuffles[0]->getType());
149 
150   // We support shuffle represents stride 4 for byte type with size of
151   // WideInstSize.
152   if (ShuffleElemSize == 64 && WideInstSize == 1024 && Factor == 4)
153      return true;
154 
155   if (ShuffleElemSize == 8 && isa<StoreInst>(Inst) && Factor == 4 &&
156       (WideInstSize == 256 || WideInstSize == 512 || WideInstSize == 1024 ||
157        WideInstSize == 2048))
158     return true;
159 
160   if (ShuffleElemSize == 8 && Factor == 3 &&
161       (WideInstSize == 384 || WideInstSize == 768 || WideInstSize == 1536))
162     return true;
163 
164   return false;
165 }
166 
167 void X86InterleavedAccessGroup::decompose(
168     Instruction *VecInst, unsigned NumSubVectors, VectorType *SubVecTy,
169     SmallVectorImpl<Instruction *> &DecomposedVectors) {
170   assert((isa<LoadInst>(VecInst) || isa<ShuffleVectorInst>(VecInst)) &&
171          "Expected Load or Shuffle");
172 
173   Type *VecWidth = VecInst->getType();
174   (void)VecWidth;
175   assert(VecWidth->isVectorTy() &&
176          DL.getTypeSizeInBits(VecWidth) >=
177              DL.getTypeSizeInBits(SubVecTy) * NumSubVectors &&
178          "Invalid Inst-size!!!");
179 
180   if (auto *SVI = dyn_cast<ShuffleVectorInst>(VecInst)) {
181     Value *Op0 = SVI->getOperand(0);
182     Value *Op1 = SVI->getOperand(1);
183 
184     // Generate N(= NumSubVectors) shuffles of T(= SubVecTy) type.
185     for (unsigned i = 0; i < NumSubVectors; ++i)
186       DecomposedVectors.push_back(
187           cast<ShuffleVectorInst>(Builder.CreateShuffleVector(
188               Op0, Op1,
189               createSequentialMask(Builder, Indices[i],
190                                    SubVecTy->getVectorNumElements(), 0))));
191     return;
192   }
193 
194   // Decompose the load instruction.
195   LoadInst *LI = cast<LoadInst>(VecInst);
196   Type *VecBaseTy, *VecBasePtrTy;
197   Value *VecBasePtr;
198   unsigned int NumLoads = NumSubVectors;
199   // In the case of stride 3 with a vector of 32 elements load the information
200   // in the following way:
201   // [0,1...,VF/2-1,VF/2+VF,VF/2+VF+1,...,2VF-1]
202   unsigned VecLength = DL.getTypeSizeInBits(VecWidth);
203   if (VecLength == 768 || VecLength == 1536) {
204     VecBaseTy = VectorType::get(Type::getInt8Ty(LI->getContext()), 16);
205     VecBasePtrTy = VecBaseTy->getPointerTo(LI->getPointerAddressSpace());
206     VecBasePtr = Builder.CreateBitCast(LI->getPointerOperand(), VecBasePtrTy);
207     NumLoads = NumSubVectors * (VecLength / 384);
208   } else {
209     VecBaseTy = SubVecTy;
210     VecBasePtrTy = VecBaseTy->getPointerTo(LI->getPointerAddressSpace());
211     VecBasePtr = Builder.CreateBitCast(LI->getPointerOperand(), VecBasePtrTy);
212   }
213   // Generate N loads of T type.
214   for (unsigned i = 0; i < NumLoads; i++) {
215     // TODO: Support inbounds GEP.
216     Value *NewBasePtr = Builder.CreateGEP(VecBasePtr, Builder.getInt32(i));
217     Instruction *NewLoad =
218         Builder.CreateAlignedLoad(VecBaseTy, NewBasePtr, LI->getAlignment());
219     DecomposedVectors.push_back(NewLoad);
220   }
221 }
222 
223 // Changing the scale of the vector type by reducing the number of elements and
224 // doubling the scalar size.
225 static MVT scaleVectorType(MVT VT) {
226   unsigned ScalarSize = VT.getVectorElementType().getScalarSizeInBits() * 2;
227   return MVT::getVectorVT(MVT::getIntegerVT(ScalarSize),
228                           VT.getVectorNumElements() / 2);
229 }
230 
231 static uint32_t Concat[] = {
232   0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15,
233   16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
234   32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
235   48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63 };
236 
237 // genShuffleBland - Creates shuffle according to two vectors.This function is
238 // only works on instructions with lane inside 256 registers. According to
239 // the mask 'Mask' creates a new Mask 'Out' by the offset of the mask. The
240 // offset amount depends on the two integer, 'LowOffset' and 'HighOffset'.
241 // Where the 'LowOffset' refers to the first vector and the highOffset refers to
242 // the second vector.
243 // |a0....a5,b0....b4,c0....c4|a16..a21,b16..b20,c16..c20|
244 // |c5...c10,a5....a9,b5....b9|c21..c26,a22..a26,b21..b25|
245 // |b10..b15,c11..c15,a10..a15|b26..b31,c27..c31,a27..a31|
246 // For the sequence to work as a mirror to the load.
247 // We must consider the elements order as above.
248 // In this function we are combining two types of shuffles.
249 // The first one is vpshufed and the second is a type of "blend" shuffle.
250 // By computing the shuffle on a sequence of 16 elements(one lane) and add the
251 // correct offset. We are creating a vpsuffed + blend sequence between two
252 // shuffles.
253 static void genShuffleBland(MVT VT, ArrayRef<uint32_t> Mask,
254   SmallVectorImpl<uint32_t> &Out, int LowOffset,
255   int HighOffset) {
256   assert(VT.getSizeInBits() >= 256 &&
257     "This function doesn't accept width smaller then 256");
258   unsigned NumOfElm = VT.getVectorNumElements();
259   for (unsigned i = 0; i < Mask.size(); i++)
260     Out.push_back(Mask[i] + LowOffset);
261   for (unsigned i = 0; i < Mask.size(); i++)
262     Out.push_back(Mask[i] + HighOffset + NumOfElm);
263 }
264 
265 // reorderSubVector returns the data to is the original state. And de-facto is
266 // the opposite of  the function concatSubVector.
267 
268 // For VecElems = 16
269 // Invec[0] -  |0|      TransposedMatrix[0] - |0|
270 // Invec[1] -  |1|  =>  TransposedMatrix[1] - |1|
271 // Invec[2] -  |2|      TransposedMatrix[2] - |2|
272 
273 // For VecElems = 32
274 // Invec[0] -  |0|3|      TransposedMatrix[0] - |0|1|
275 // Invec[1] -  |1|4|  =>  TransposedMatrix[1] - |2|3|
276 // Invec[2] -  |2|5|      TransposedMatrix[2] - |4|5|
277 
278 // For VecElems = 64
279 // Invec[0] -  |0|3|6|9 |     TransposedMatrix[0] - |0|1|2 |3 |
280 // Invec[1] -  |1|4|7|10| =>  TransposedMatrix[1] - |4|5|6 |7 |
281 // Invec[2] -  |2|5|8|11|     TransposedMatrix[2] - |8|9|10|11|
282 
283 static void reorderSubVector(MVT VT, SmallVectorImpl<Value *> &TransposedMatrix,
284   ArrayRef<Value *> Vec, ArrayRef<uint32_t> VPShuf,
285   unsigned VecElems, unsigned Stride,
286   IRBuilder<> Builder) {
287 
288   if (VecElems == 16) {
289     for (unsigned i = 0; i < Stride; i++)
290       TransposedMatrix[i] = Builder.CreateShuffleVector(
291         Vec[i], UndefValue::get(Vec[i]->getType()), VPShuf);
292     return;
293   }
294 
295   SmallVector<uint32_t, 32> OptimizeShuf;
296   Value *Temp[8];
297 
298   for (unsigned i = 0; i < (VecElems / 16) * Stride; i += 2) {
299     genShuffleBland(VT, VPShuf, OptimizeShuf, (i / Stride) * 16,
300       (i + 1) / Stride * 16);
301     Temp[i / 2] = Builder.CreateShuffleVector(
302       Vec[i % Stride], Vec[(i + 1) % Stride], OptimizeShuf);
303     OptimizeShuf.clear();
304   }
305 
306   if (VecElems == 32) {
307     std::copy(Temp, Temp + Stride, TransposedMatrix.begin());
308     return;
309   }
310   else
311     for (unsigned i = 0; i < Stride; i++)
312       TransposedMatrix[i] =
313       Builder.CreateShuffleVector(Temp[2 * i], Temp[2 * i + 1], Concat);
314 }
315 
316 void X86InterleavedAccessGroup::interleave8bitStride4VF8(
317     ArrayRef<Instruction *> Matrix,
318     SmallVectorImpl<Value *> &TransposedMatrix) {
319   // Assuming we start from the following vectors:
320   // Matrix[0]= c0 c1 c2 c3 c4 ... c7
321   // Matrix[1]= m0 m1 m2 m3 m4 ... m7
322   // Matrix[2]= y0 y1 y2 y3 y4 ... y7
323   // Matrix[3]= k0 k1 k2 k3 k4 ... k7
324 
325   MVT VT = MVT::v8i16;
326   TransposedMatrix.resize(2);
327   SmallVector<uint32_t, 16> MaskLow;
328   SmallVector<uint32_t, 32> MaskLowTemp1, MaskLowWord;
329   SmallVector<uint32_t, 32> MaskHighTemp1, MaskHighWord;
330 
331   for (unsigned i = 0; i < 8; ++i) {
332     MaskLow.push_back(i);
333     MaskLow.push_back(i + 8);
334   }
335 
336   createUnpackShuffleMask<uint32_t>(VT, MaskLowTemp1, true, false);
337   createUnpackShuffleMask<uint32_t>(VT, MaskHighTemp1, false, false);
338   scaleShuffleMask<uint32_t>(2, MaskHighTemp1, MaskHighWord);
339   scaleShuffleMask<uint32_t>(2, MaskLowTemp1, MaskLowWord);
340   // IntrVec1Low = c0 m0 c1 m1 c2 m2 c3 m3 c4 m4 c5 m5 c6 m6 c7 m7
341   // IntrVec2Low = y0 k0 y1 k1 y2 k2 y3 k3 y4 k4 y5 k5 y6 k6 y7 k7
342   Value *IntrVec1Low =
343       Builder.CreateShuffleVector(Matrix[0], Matrix[1], MaskLow);
344   Value *IntrVec2Low =
345       Builder.CreateShuffleVector(Matrix[2], Matrix[3], MaskLow);
346 
347   // TransposedMatrix[0] = c0 m0 y0 k0 c1 m1 y1 k1 c2 m2 y2 k2 c3 m3 y3 k3
348   // TransposedMatrix[1] = c4 m4 y4 k4 c5 m5 y5 k5 c6 m6 y6 k6 c7 m7 y7 k7
349 
350   TransposedMatrix[0] =
351       Builder.CreateShuffleVector(IntrVec1Low, IntrVec2Low, MaskLowWord);
352   TransposedMatrix[1] =
353       Builder.CreateShuffleVector(IntrVec1Low, IntrVec2Low, MaskHighWord);
354 }
355 
356 void X86InterleavedAccessGroup::interleave8bitStride4(
357     ArrayRef<Instruction *> Matrix, SmallVectorImpl<Value *> &TransposedMatrix,
358     unsigned NumOfElm) {
359   // Example: Assuming we start from the following vectors:
360   // Matrix[0]= c0 c1 c2 c3 c4 ... c31
361   // Matrix[1]= m0 m1 m2 m3 m4 ... m31
362   // Matrix[2]= y0 y1 y2 y3 y4 ... y31
363   // Matrix[3]= k0 k1 k2 k3 k4 ... k31
364 
365   MVT VT = MVT::getVectorVT(MVT::i8, NumOfElm);
366   MVT HalfVT = scaleVectorType(VT);
367 
368   TransposedMatrix.resize(4);
369   SmallVector<uint32_t, 32> MaskHigh;
370   SmallVector<uint32_t, 32> MaskLow;
371   SmallVector<uint32_t, 32> LowHighMask[2];
372   SmallVector<uint32_t, 32> MaskHighTemp;
373   SmallVector<uint32_t, 32> MaskLowTemp;
374 
375   // MaskHighTemp and MaskLowTemp built in the vpunpckhbw and vpunpcklbw X86
376   // shuffle pattern.
377 
378   createUnpackShuffleMask<uint32_t>(VT, MaskLow, true, false);
379   createUnpackShuffleMask<uint32_t>(VT, MaskHigh, false, false);
380 
381   // MaskHighTemp1 and MaskLowTemp1 built in the vpunpckhdw and vpunpckldw X86
382   // shuffle pattern.
383 
384   createUnpackShuffleMask<uint32_t>(HalfVT, MaskLowTemp, true, false);
385   createUnpackShuffleMask<uint32_t>(HalfVT, MaskHighTemp, false, false);
386   scaleShuffleMask<uint32_t>(2, MaskLowTemp, LowHighMask[0]);
387   scaleShuffleMask<uint32_t>(2, MaskHighTemp, LowHighMask[1]);
388 
389   // IntrVec1Low  = c0  m0  c1  m1 ... c7  m7  | c16 m16 c17 m17 ... c23 m23
390   // IntrVec1High = c8  m8  c9  m9 ... c15 m15 | c24 m24 c25 m25 ... c31 m31
391   // IntrVec2Low  = y0  k0  y1  k1 ... y7  k7  | y16 k16 y17 k17 ... y23 k23
392   // IntrVec2High = y8  k8  y9  k9 ... y15 k15 | y24 k24 y25 k25 ... y31 k31
393   Value *IntrVec[4];
394 
395   IntrVec[0] = Builder.CreateShuffleVector(Matrix[0], Matrix[1], MaskLow);
396   IntrVec[1] = Builder.CreateShuffleVector(Matrix[0], Matrix[1], MaskHigh);
397   IntrVec[2] = Builder.CreateShuffleVector(Matrix[2], Matrix[3], MaskLow);
398   IntrVec[3] = Builder.CreateShuffleVector(Matrix[2], Matrix[3], MaskHigh);
399 
400   // cmyk4  cmyk5  cmyk6   cmyk7  | cmyk20 cmyk21 cmyk22 cmyk23
401   // cmyk12 cmyk13 cmyk14  cmyk15 | cmyk28 cmyk29 cmyk30 cmyk31
402   // cmyk0  cmyk1  cmyk2   cmyk3  | cmyk16 cmyk17 cmyk18 cmyk19
403   // cmyk8  cmyk9  cmyk10  cmyk11 | cmyk24 cmyk25 cmyk26 cmyk27
404 
405   Value *VecOut[4];
406   for (int i = 0; i < 4; i++)
407     VecOut[i] = Builder.CreateShuffleVector(IntrVec[i / 2], IntrVec[i / 2 + 2],
408                                             LowHighMask[i % 2]);
409 
410   // cmyk0  cmyk1  cmyk2  cmyk3   | cmyk4  cmyk5  cmyk6  cmyk7
411   // cmyk8  cmyk9  cmyk10 cmyk11  | cmyk12 cmyk13 cmyk14 cmyk15
412   // cmyk16 cmyk17 cmyk18 cmyk19  | cmyk20 cmyk21 cmyk22 cmyk23
413   // cmyk24 cmyk25 cmyk26 cmyk27  | cmyk28 cmyk29 cmyk30 cmyk31
414 
415   if (VT == MVT::v16i8) {
416     std::copy(VecOut, VecOut + 4, TransposedMatrix.begin());
417     return;
418   }
419 
420   reorderSubVector(VT, TransposedMatrix, VecOut, makeArrayRef(Concat, 16),
421 		   NumOfElm, 4, Builder);
422 }
423 
424 //  createShuffleStride returns shuffle mask of size N.
425 //  The shuffle pattern is as following :
426 //  {0, Stride%(VF/Lane), (2*Stride%(VF/Lane))...(VF*Stride/Lane)%(VF/Lane),
427 //  (VF/ Lane) ,(VF / Lane)+Stride%(VF/Lane),...,
428 //  (VF / Lane)+(VF*Stride/Lane)%(VF/Lane)}
429 //  Where Lane is the # of lanes in a register:
430 //  VectorSize = 128 => Lane = 1
431 //  VectorSize = 256 => Lane = 2
432 //  For example shuffle pattern for VF 16 register size 256 -> lanes = 2
433 //  {<[0|3|6|1|4|7|2|5]-[8|11|14|9|12|15|10|13]>}
434 static void createShuffleStride(MVT VT, int Stride,
435                                 SmallVectorImpl<uint32_t> &Mask) {
436   int VectorSize = VT.getSizeInBits();
437   int VF = VT.getVectorNumElements();
438   int LaneCount = std::max(VectorSize / 128, 1);
439   for (int Lane = 0; Lane < LaneCount; Lane++)
440     for (int i = 0, LaneSize = VF / LaneCount; i != LaneSize; ++i)
441       Mask.push_back((i * Stride) % LaneSize + LaneSize * Lane);
442 }
443 
444 //  setGroupSize sets 'SizeInfo' to the size(number of elements) of group
445 //  inside mask a shuffleMask. A mask contains exactly 3 groups, where
446 //  each group is a monotonically increasing sequence with stride 3.
447 //  For example shuffleMask {0,3,6,1,4,7,2,5} => {3,3,2}
448 static void setGroupSize(MVT VT, SmallVectorImpl<uint32_t> &SizeInfo) {
449   int VectorSize = VT.getSizeInBits();
450   int VF = VT.getVectorNumElements() / std::max(VectorSize / 128, 1);
451   for (int i = 0, FirstGroupElement = 0; i < 3; i++) {
452     int GroupSize = std::ceil((VF - FirstGroupElement) / 3.0);
453     SizeInfo.push_back(GroupSize);
454     FirstGroupElement = ((GroupSize)*3 + FirstGroupElement) % VF;
455   }
456 }
457 
458 //  DecodePALIGNRMask returns the shuffle mask of vpalign instruction.
459 //  vpalign works according to lanes
460 //  Where Lane is the # of lanes in a register:
461 //  VectorWide = 128 => Lane = 1
462 //  VectorWide = 256 => Lane = 2
463 //  For Lane = 1 shuffle pattern is: {DiffToJump,...,DiffToJump+VF-1}.
464 //  For Lane = 2 shuffle pattern is:
465 //  {DiffToJump,...,VF/2-1,VF,...,DiffToJump+VF-1}.
466 //  Imm variable sets the offset amount. The result of the
467 //  function is stored inside ShuffleMask vector and it built as described in
468 //  the begin of the description. AlignDirection is a boolean that indicates the
469 //  direction of the alignment. (false - align to the "right" side while true -
470 //  align to the "left" side)
471 static void DecodePALIGNRMask(MVT VT, unsigned Imm,
472                               SmallVectorImpl<uint32_t> &ShuffleMask,
473                               bool AlignDirection = true, bool Unary = false) {
474   unsigned NumElts = VT.getVectorNumElements();
475   unsigned NumLanes = std::max((int)VT.getSizeInBits() / 128, 1);
476   unsigned NumLaneElts = NumElts / NumLanes;
477 
478   Imm = AlignDirection ? Imm : (NumLaneElts - Imm);
479   unsigned Offset = Imm * (VT.getScalarSizeInBits() / 8);
480 
481   for (unsigned l = 0; l != NumElts; l += NumLaneElts) {
482     for (unsigned i = 0; i != NumLaneElts; ++i) {
483       unsigned Base = i + Offset;
484       // if i+offset is out of this lane then we actually need the other source
485       // If Unary the other source is the first source.
486       if (Base >= NumLaneElts)
487         Base = Unary ? Base % NumLaneElts : Base + NumElts - NumLaneElts;
488       ShuffleMask.push_back(Base + l);
489     }
490   }
491 }
492 
493 // concatSubVector - The function rebuilds the data to a correct expected
494 // order. An assumption(The shape of the matrix) was taken for the
495 // deinterleaved to work with lane's instructions like 'vpalign' or 'vphuf'.
496 // This function ensures that the data is built in correct way for the lane
497 // instructions. Each lane inside the vector is a 128-bit length.
498 //
499 // The 'InVec' argument contains the data in increasing order. In InVec[0] You
500 // can find the first 128 bit data. The number of different lanes inside a
501 // vector depends on the 'VecElems'.In general, the formula is
502 // VecElems * type / 128. The size of the array 'InVec' depends and equal to
503 // 'VecElems'.
504 
505 // For VecElems = 16
506 // Invec[0] - |0|      Vec[0] - |0|
507 // Invec[1] - |1|  =>  Vec[1] - |1|
508 // Invec[2] - |2|      Vec[2] - |2|
509 
510 // For VecElems = 32
511 // Invec[0] - |0|1|      Vec[0] - |0|3|
512 // Invec[1] - |2|3|  =>  Vec[1] - |1|4|
513 // Invec[2] - |4|5|      Vec[2] - |2|5|
514 
515 // For VecElems = 64
516 // Invec[0] - |0|1|2 |3 |      Vec[0] - |0|3|6|9 |
517 // Invec[1] - |4|5|6 |7 |  =>  Vec[1] - |1|4|7|10|
518 // Invec[2] - |8|9|10|11|      Vec[2] - |2|5|8|11|
519 
520 static void concatSubVector(Value **Vec, ArrayRef<Instruction *> InVec,
521                             unsigned VecElems, IRBuilder<> Builder) {
522   if (VecElems == 16) {
523     for (int i = 0; i < 3; i++)
524       Vec[i] = InVec[i];
525     return;
526   }
527 
528   for (unsigned j = 0; j < VecElems / 32; j++)
529     for (int i = 0; i < 3; i++)
530       Vec[i + j * 3] = Builder.CreateShuffleVector(
531           InVec[j * 6 + i], InVec[j * 6 + i + 3], makeArrayRef(Concat, 32));
532 
533   if (VecElems == 32)
534     return;
535 
536   for (int i = 0; i < 3; i++)
537     Vec[i] = Builder.CreateShuffleVector(Vec[i], Vec[i + 3], Concat);
538 }
539 
540 void X86InterleavedAccessGroup::deinterleave8bitStride3(
541     ArrayRef<Instruction *> InVec, SmallVectorImpl<Value *> &TransposedMatrix,
542     unsigned VecElems) {
543   // Example: Assuming we start from the following vectors:
544   // Matrix[0]= a0 b0 c0 a1 b1 c1 a2 b2
545   // Matrix[1]= c2 a3 b3 c3 a4 b4 c4 a5
546   // Matrix[2]= b5 c5 a6 b6 c6 a7 b7 c7
547 
548   TransposedMatrix.resize(3);
549   SmallVector<uint32_t, 32> VPShuf;
550   SmallVector<uint32_t, 32> VPAlign[2];
551   SmallVector<uint32_t, 32> VPAlign2;
552   SmallVector<uint32_t, 32> VPAlign3;
553   SmallVector<uint32_t, 3> GroupSize;
554   Value *Vec[6], *TempVector[3];
555 
556   MVT VT = MVT::getVT(Shuffles[0]->getType());
557 
558   createShuffleStride(VT, 3, VPShuf);
559   setGroupSize(VT, GroupSize);
560 
561   for (int i = 0; i < 2; i++)
562     DecodePALIGNRMask(VT, GroupSize[2 - i], VPAlign[i], false);
563 
564   DecodePALIGNRMask(VT, GroupSize[2] + GroupSize[1], VPAlign2, true, true);
565   DecodePALIGNRMask(VT, GroupSize[1], VPAlign3, true, true);
566 
567   concatSubVector(Vec, InVec, VecElems, Builder);
568   // Vec[0]= a0 a1 a2 b0 b1 b2 c0 c1
569   // Vec[1]= c2 c3 c4 a3 a4 a5 b3 b4
570   // Vec[2]= b5 b6 b7 c5 c6 c7 a6 a7
571 
572   for (int i = 0; i < 3; i++)
573     Vec[i] = Builder.CreateShuffleVector(
574         Vec[i], UndefValue::get(Vec[0]->getType()), VPShuf);
575 
576   // TempVector[0]= a6 a7 a0 a1 a2 b0 b1 b2
577   // TempVector[1]= c0 c1 c2 c3 c4 a3 a4 a5
578   // TempVector[2]= b3 b4 b5 b6 b7 c5 c6 c7
579 
580   for (int i = 0; i < 3; i++)
581     TempVector[i] =
582         Builder.CreateShuffleVector(Vec[(i + 2) % 3], Vec[i], VPAlign[0]);
583 
584   // Vec[0]= a3 a4 a5 a6 a7 a0 a1 a2
585   // Vec[1]= c5 c6 c7 c0 c1 c2 c3 c4
586   // Vec[2]= b0 b1 b2 b3 b4 b5 b6 b7
587 
588   for (int i = 0; i < 3; i++)
589     Vec[i] = Builder.CreateShuffleVector(TempVector[(i + 1) % 3], TempVector[i],
590                                          VPAlign[1]);
591 
592   // TransposedMatrix[0]= a0 a1 a2 a3 a4 a5 a6 a7
593   // TransposedMatrix[1]= b0 b1 b2 b3 b4 b5 b6 b7
594   // TransposedMatrix[2]= c0 c1 c2 c3 c4 c5 c6 c7
595 
596   Value *TempVec = Builder.CreateShuffleVector(
597       Vec[1], UndefValue::get(Vec[1]->getType()), VPAlign3);
598   TransposedMatrix[0] = Builder.CreateShuffleVector(
599       Vec[0], UndefValue::get(Vec[1]->getType()), VPAlign2);
600   TransposedMatrix[1] = VecElems == 8 ? Vec[2] : TempVec;
601   TransposedMatrix[2] = VecElems == 8 ? TempVec : Vec[2];
602 }
603 
604 // group2Shuffle reorder the shuffle stride back into continuous order.
605 // For example For VF16 with Mask1 = {0,3,6,9,12,15,2,5,8,11,14,1,4,7,10,13} =>
606 // MaskResult = {0,11,6,1,12,7,2,13,8,3,14,9,4,15,10,5}.
607 static void group2Shuffle(MVT VT, SmallVectorImpl<uint32_t> &Mask,
608                           SmallVectorImpl<uint32_t> &Output) {
609   int IndexGroup[3] = {0, 0, 0};
610   int Index = 0;
611   int VectorWidth = VT.getSizeInBits();
612   int VF = VT.getVectorNumElements();
613   // Find the index of the different groups.
614   int Lane = (VectorWidth / 128 > 0) ? VectorWidth / 128 : 1;
615   for (int i = 0; i < 3; i++) {
616     IndexGroup[(Index * 3) % (VF / Lane)] = Index;
617     Index += Mask[i];
618   }
619   // According to the index compute the convert mask.
620   for (int i = 0; i < VF / Lane; i++) {
621     Output.push_back(IndexGroup[i % 3]);
622     IndexGroup[i % 3]++;
623   }
624 }
625 
626 void X86InterleavedAccessGroup::interleave8bitStride3(
627     ArrayRef<Instruction *> InVec, SmallVectorImpl<Value *> &TransposedMatrix,
628     unsigned VecElems) {
629   // Example: Assuming we start from the following vectors:
630   // Matrix[0]= a0 a1 a2 a3 a4 a5 a6 a7
631   // Matrix[1]= b0 b1 b2 b3 b4 b5 b6 b7
632   // Matrix[2]= c0 c1 c2 c3 c3 a7 b7 c7
633 
634   TransposedMatrix.resize(3);
635   SmallVector<uint32_t, 3> GroupSize;
636   SmallVector<uint32_t, 32> VPShuf;
637   SmallVector<uint32_t, 32> VPAlign[3];
638   SmallVector<uint32_t, 32> VPAlign2;
639   SmallVector<uint32_t, 32> VPAlign3;
640 
641   Value *Vec[3], *TempVector[3];
642   MVT VT = MVT::getVectorVT(MVT::i8, VecElems);
643 
644   setGroupSize(VT, GroupSize);
645 
646   for (int i = 0; i < 3; i++)
647     DecodePALIGNRMask(VT, GroupSize[i], VPAlign[i]);
648 
649   DecodePALIGNRMask(VT, GroupSize[1] + GroupSize[2], VPAlign2, false, true);
650   DecodePALIGNRMask(VT, GroupSize[1], VPAlign3, false, true);
651 
652   // Vec[0]= a3 a4 a5 a6 a7 a0 a1 a2
653   // Vec[1]= c5 c6 c7 c0 c1 c2 c3 c4
654   // Vec[2]= b0 b1 b2 b3 b4 b5 b6 b7
655 
656   Vec[0] = Builder.CreateShuffleVector(
657       InVec[0], UndefValue::get(InVec[0]->getType()), VPAlign2);
658   Vec[1] = Builder.CreateShuffleVector(
659       InVec[1], UndefValue::get(InVec[1]->getType()), VPAlign3);
660   Vec[2] = InVec[2];
661 
662   // Vec[0]= a6 a7 a0 a1 a2 b0 b1 b2
663   // Vec[1]= c0 c1 c2 c3 c4 a3 a4 a5
664   // Vec[2]= b3 b4 b5 b6 b7 c5 c6 c7
665 
666   for (int i = 0; i < 3; i++)
667     TempVector[i] =
668         Builder.CreateShuffleVector(Vec[i], Vec[(i + 2) % 3], VPAlign[1]);
669 
670   // Vec[0]= a0 a1 a2 b0 b1 b2 c0 c1
671   // Vec[1]= c2 c3 c4 a3 a4 a5 b3 b4
672   // Vec[2]= b5 b6 b7 c5 c6 c7 a6 a7
673 
674   for (int i = 0; i < 3; i++)
675     Vec[i] = Builder.CreateShuffleVector(TempVector[i], TempVector[(i + 1) % 3],
676                                          VPAlign[2]);
677 
678   // TransposedMatrix[0] = a0 b0 c0 a1 b1 c1 a2 b2
679   // TransposedMatrix[1] = c2 a3 b3 c3 a4 b4 c4 a5
680   // TransposedMatrix[2] = b5 c5 a6 b6 c6 a7 b7 c7
681 
682   unsigned NumOfElm = VT.getVectorNumElements();
683   group2Shuffle(VT, GroupSize, VPShuf);
684   reorderSubVector(VT, TransposedMatrix, Vec, VPShuf, NumOfElm,3, Builder);
685 }
686 
687 void X86InterleavedAccessGroup::transpose_4x4(
688     ArrayRef<Instruction *> Matrix,
689     SmallVectorImpl<Value *> &TransposedMatrix) {
690   assert(Matrix.size() == 4 && "Invalid matrix size");
691   TransposedMatrix.resize(4);
692 
693   // dst = src1[0,1],src2[0,1]
694   uint32_t IntMask1[] = {0, 1, 4, 5};
695   ArrayRef<uint32_t> Mask = makeArrayRef(IntMask1, 4);
696   Value *IntrVec1 = Builder.CreateShuffleVector(Matrix[0], Matrix[2], Mask);
697   Value *IntrVec2 = Builder.CreateShuffleVector(Matrix[1], Matrix[3], Mask);
698 
699   // dst = src1[2,3],src2[2,3]
700   uint32_t IntMask2[] = {2, 3, 6, 7};
701   Mask = makeArrayRef(IntMask2, 4);
702   Value *IntrVec3 = Builder.CreateShuffleVector(Matrix[0], Matrix[2], Mask);
703   Value *IntrVec4 = Builder.CreateShuffleVector(Matrix[1], Matrix[3], Mask);
704 
705   // dst = src1[0],src2[0],src1[2],src2[2]
706   uint32_t IntMask3[] = {0, 4, 2, 6};
707   Mask = makeArrayRef(IntMask3, 4);
708   TransposedMatrix[0] = Builder.CreateShuffleVector(IntrVec1, IntrVec2, Mask);
709   TransposedMatrix[2] = Builder.CreateShuffleVector(IntrVec3, IntrVec4, Mask);
710 
711   // dst = src1[1],src2[1],src1[3],src2[3]
712   uint32_t IntMask4[] = {1, 5, 3, 7};
713   Mask = makeArrayRef(IntMask4, 4);
714   TransposedMatrix[1] = Builder.CreateShuffleVector(IntrVec1, IntrVec2, Mask);
715   TransposedMatrix[3] = Builder.CreateShuffleVector(IntrVec3, IntrVec4, Mask);
716 }
717 
718 // Lowers this interleaved access group into X86-specific
719 // instructions/intrinsics.
720 bool X86InterleavedAccessGroup::lowerIntoOptimizedSequence() {
721   SmallVector<Instruction *, 4> DecomposedVectors;
722   SmallVector<Value *, 4> TransposedVectors;
723   VectorType *ShuffleTy = Shuffles[0]->getType();
724 
725   if (isa<LoadInst>(Inst)) {
726     // Try to generate target-sized register(/instruction).
727     decompose(Inst, Factor, ShuffleTy, DecomposedVectors);
728 
729     Type *ShuffleEltTy = Inst->getType();
730     unsigned NumSubVecElems = ShuffleEltTy->getVectorNumElements() / Factor;
731     // Perform matrix-transposition in order to compute interleaved
732     // results by generating some sort of (optimized) target-specific
733     // instructions.
734 
735     switch (NumSubVecElems) {
736     default:
737       return false;
738     case 4:
739       transpose_4x4(DecomposedVectors, TransposedVectors);
740       break;
741     case 8:
742     case 16:
743     case 32:
744     case 64:
745       deinterleave8bitStride3(DecomposedVectors, TransposedVectors,
746                               NumSubVecElems);
747       break;
748     }
749 
750     // Now replace the unoptimized-interleaved-vectors with the
751     // transposed-interleaved vectors.
752     for (unsigned i = 0, e = Shuffles.size(); i < e; ++i)
753       Shuffles[i]->replaceAllUsesWith(TransposedVectors[Indices[i]]);
754 
755     return true;
756   }
757 
758   Type *ShuffleEltTy = ShuffleTy->getVectorElementType();
759   unsigned NumSubVecElems = ShuffleTy->getVectorNumElements() / Factor;
760 
761   // Lower the interleaved stores:
762   //   1. Decompose the interleaved wide shuffle into individual shuffle
763   //   vectors.
764   decompose(Shuffles[0], Factor, VectorType::get(ShuffleEltTy, NumSubVecElems),
765             DecomposedVectors);
766 
767   //   2. Transpose the interleaved-vectors into vectors of contiguous
768   //      elements.
769   switch (NumSubVecElems) {
770   case 4:
771     transpose_4x4(DecomposedVectors, TransposedVectors);
772     break;
773   case 8:
774     interleave8bitStride4VF8(DecomposedVectors, TransposedVectors);
775     break;
776   case 16:
777   case 32:
778   case 64:
779     if (Factor == 4)
780       interleave8bitStride4(DecomposedVectors, TransposedVectors,
781                             NumSubVecElems);
782     if (Factor == 3)
783       interleave8bitStride3(DecomposedVectors, TransposedVectors,
784                             NumSubVecElems);
785     break;
786   default:
787     return false;
788   }
789 
790   //   3. Concatenate the contiguous-vectors back into a wide vector.
791   Value *WideVec = concatenateVectors(Builder, TransposedVectors);
792 
793   //   4. Generate a store instruction for wide-vec.
794   StoreInst *SI = cast<StoreInst>(Inst);
795   Builder.CreateAlignedStore(WideVec, SI->getPointerOperand(),
796                              SI->getAlignment());
797 
798   return true;
799 }
800 
801 // Lower interleaved load(s) into target specific instructions/
802 // intrinsics. Lowering sequence varies depending on the vector-types, factor,
803 // number of shuffles and ISA.
804 // Currently, lowering is supported for 4x64 bits with Factor = 4 on AVX.
805 bool X86TargetLowering::lowerInterleavedLoad(
806     LoadInst *LI, ArrayRef<ShuffleVectorInst *> Shuffles,
807     ArrayRef<unsigned> Indices, unsigned Factor) const {
808   assert(Factor >= 2 && Factor <= getMaxSupportedInterleaveFactor() &&
809          "Invalid interleave factor");
810   assert(!Shuffles.empty() && "Empty shufflevector input");
811   assert(Shuffles.size() == Indices.size() &&
812          "Unmatched number of shufflevectors and indices");
813 
814   // Create an interleaved access group.
815   IRBuilder<> Builder(LI);
816   X86InterleavedAccessGroup Grp(LI, Shuffles, Indices, Factor, Subtarget,
817                                 Builder);
818 
819   return Grp.isSupported() && Grp.lowerIntoOptimizedSequence();
820 }
821 
822 bool X86TargetLowering::lowerInterleavedStore(StoreInst *SI,
823                                               ShuffleVectorInst *SVI,
824                                               unsigned Factor) const {
825   assert(Factor >= 2 && Factor <= getMaxSupportedInterleaveFactor() &&
826          "Invalid interleave factor");
827 
828   assert(SVI->getType()->getVectorNumElements() % Factor == 0 &&
829          "Invalid interleaved store");
830 
831   // Holds the indices of SVI that correspond to the starting index of each
832   // interleaved shuffle.
833   SmallVector<unsigned, 4> Indices;
834   auto Mask = SVI->getShuffleMask();
835   for (unsigned i = 0; i < Factor; i++)
836     Indices.push_back(Mask[i]);
837 
838   ArrayRef<ShuffleVectorInst *> Shuffles = makeArrayRef(SVI);
839 
840   // Create an interleaved access group.
841   IRBuilder<> Builder(SI);
842   X86InterleavedAccessGroup Grp(SI, Shuffles, Indices, Factor, Subtarget,
843                                 Builder);
844 
845   return Grp.isSupported() && Grp.lowerIntoOptimizedSequence();
846 }
847