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