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