169653af7SCraig Topper //===-- X86ShuffleDecodeConstantPool.cpp - X86 shuffle decode -------------===//
269653af7SCraig Topper //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
669653af7SCraig Topper //
769653af7SCraig Topper //===----------------------------------------------------------------------===//
869653af7SCraig Topper //
969653af7SCraig Topper // Define several functions to decode x86 specific shuffle semantics using
1069653af7SCraig Topper // constants from the constant pool.
1169653af7SCraig Topper //
1269653af7SCraig Topper //===----------------------------------------------------------------------===//
1369653af7SCraig Topper 
14f5ad93d2SSimon Pilgrim #include "X86ShuffleDecodeConstantPool.h"
156dbf1a12SCraig Topper #include "MCTargetDesc/X86ShuffleDecode.h"
1653e5a38dSCraig Topper #include "llvm/ADT/APInt.h"
17f5ad93d2SSimon Pilgrim #include "llvm/ADT/SmallVector.h"
1869653af7SCraig Topper #include "llvm/IR/Constants.h"
1969653af7SCraig Topper 
2069653af7SCraig Topper //===----------------------------------------------------------------------===//
2169653af7SCraig Topper //  Vector Mask Decoding
2269653af7SCraig Topper //===----------------------------------------------------------------------===//
2369653af7SCraig Topper 
2469653af7SCraig Topper namespace llvm {
2569653af7SCraig Topper 
extractConstantMask(const Constant * C,unsigned MaskEltSizeInBits,APInt & UndefElts,SmallVectorImpl<uint64_t> & RawMask)2697a4820cSSimon Pilgrim static bool extractConstantMask(const Constant *C, unsigned MaskEltSizeInBits,
2753e5a38dSCraig Topper                                 APInt &UndefElts,
2897a4820cSSimon Pilgrim                                 SmallVectorImpl<uint64_t> &RawMask) {
2997a4820cSSimon Pilgrim   // It is not an error for shuffle masks to not be a vector of
3097a4820cSSimon Pilgrim   // MaskEltSizeInBits because the constant pool uniques constants by their
3197a4820cSSimon Pilgrim   // bit representation.
3269653af7SCraig Topper   // e.g. the following take up the same space in the constant pool:
3369653af7SCraig Topper   //   i128 -170141183420855150465331762880109871104
3469653af7SCraig Topper   //
3569653af7SCraig Topper   //   <2 x i64> <i64 -9223372034707292160, i64 -9223372034707292160>
3669653af7SCraig Topper   //
3769653af7SCraig Topper   //   <4 x i32> <i32 -2147483648, i32 -2147483648,
3869653af7SCraig Topper   //              i32 -2147483648, i32 -2147483648>
390da1e7ebSChristopher Tetreault   auto *CstTy = dyn_cast<FixedVectorType>(C->getType());
40dd24fb38SChristopher Tetreault   if (!CstTy)
4197a4820cSSimon Pilgrim     return false;
4269653af7SCraig Topper 
43dd24fb38SChristopher Tetreault   Type *CstEltTy = CstTy->getElementType();
4497a4820cSSimon Pilgrim   if (!CstEltTy->isIntegerTy())
4597a4820cSSimon Pilgrim     return false;
4669653af7SCraig Topper 
4797a4820cSSimon Pilgrim   unsigned CstSizeInBits = CstTy->getPrimitiveSizeInBits();
4897a4820cSSimon Pilgrim   unsigned CstEltSizeInBits = CstTy->getScalarSizeInBits();
49dd24fb38SChristopher Tetreault   unsigned NumCstElts = CstTy->getNumElements();
5069653af7SCraig Topper 
51e86b7e22SSimon Pilgrim   assert((CstSizeInBits % MaskEltSizeInBits) == 0 &&
52e86b7e22SSimon Pilgrim          "Unaligned shuffle mask size");
53e86b7e22SSimon Pilgrim 
54e86b7e22SSimon Pilgrim   unsigned NumMaskElts = CstSizeInBits / MaskEltSizeInBits;
55e86b7e22SSimon Pilgrim   UndefElts = APInt(NumMaskElts, 0);
56e86b7e22SSimon Pilgrim   RawMask.resize(NumMaskElts, 0);
57e86b7e22SSimon Pilgrim 
58e86b7e22SSimon Pilgrim   // Fast path - if the constants match the mask size then copy direct.
59e86b7e22SSimon Pilgrim   if (MaskEltSizeInBits == CstEltSizeInBits) {
60e86b7e22SSimon Pilgrim     assert(NumCstElts == NumMaskElts && "Unaligned shuffle mask size");
61e86b7e22SSimon Pilgrim     for (unsigned i = 0; i != NumMaskElts; ++i) {
62e86b7e22SSimon Pilgrim       Constant *COp = C->getAggregateElement(i);
63e86b7e22SSimon Pilgrim       if (!COp || (!isa<UndefValue>(COp) && !isa<ConstantInt>(COp)))
64e86b7e22SSimon Pilgrim         return false;
65e86b7e22SSimon Pilgrim 
66e86b7e22SSimon Pilgrim       if (isa<UndefValue>(COp)) {
67e86b7e22SSimon Pilgrim         UndefElts.setBit(i);
68e86b7e22SSimon Pilgrim         RawMask[i] = 0;
69e86b7e22SSimon Pilgrim         continue;
70e86b7e22SSimon Pilgrim       }
71e86b7e22SSimon Pilgrim 
72e86b7e22SSimon Pilgrim       auto *Elt = cast<ConstantInt>(COp);
73e86b7e22SSimon Pilgrim       RawMask[i] = Elt->getValue().getZExtValue();
74e86b7e22SSimon Pilgrim     }
75e86b7e22SSimon Pilgrim     return true;
76e86b7e22SSimon Pilgrim   }
77e86b7e22SSimon Pilgrim 
7897a4820cSSimon Pilgrim   // Extract all the undef/constant element data and pack into single bitsets.
7997a4820cSSimon Pilgrim   APInt UndefBits(CstSizeInBits, 0);
8097a4820cSSimon Pilgrim   APInt MaskBits(CstSizeInBits, 0);
8197a4820cSSimon Pilgrim   for (unsigned i = 0; i != NumCstElts; ++i) {
8269653af7SCraig Topper     Constant *COp = C->getAggregateElement(i);
8397a4820cSSimon Pilgrim     if (!COp || (!isa<UndefValue>(COp) && !isa<ConstantInt>(COp)))
8497a4820cSSimon Pilgrim       return false;
8597a4820cSSimon Pilgrim 
863a895c48SSimon Pilgrim     unsigned BitOffset = i * CstEltSizeInBits;
873a895c48SSimon Pilgrim 
8897a4820cSSimon Pilgrim     if (isa<UndefValue>(COp)) {
89aed35227SSimon Pilgrim       UndefBits.setBits(BitOffset, BitOffset + CstEltSizeInBits);
9069653af7SCraig Topper       continue;
9169653af7SCraig Topper     }
9205e48b95SSimon Pilgrim 
93b02667c4SSimon Pilgrim     MaskBits.insertBits(cast<ConstantInt>(COp)->getValue(), BitOffset);
9497a4820cSSimon Pilgrim   }
9505e48b95SSimon Pilgrim 
9697a4820cSSimon Pilgrim   // Now extract the undef/constant bit data into the raw shuffle masks.
9797a4820cSSimon Pilgrim   for (unsigned i = 0; i != NumMaskElts; ++i) {
980f5fb5f5SSimon Pilgrim     unsigned BitOffset = i * MaskEltSizeInBits;
990f5fb5f5SSimon Pilgrim     APInt EltUndef = UndefBits.extractBits(MaskEltSizeInBits, BitOffset);
10097a4820cSSimon Pilgrim 
10197a4820cSSimon Pilgrim     // Only treat the element as UNDEF if all bits are UNDEF, otherwise
10297a4820cSSimon Pilgrim     // treat it as zero.
103*a9bceb2bSJay Foad     if (EltUndef.isAllOnes()) {
10453e5a38dSCraig Topper       UndefElts.setBit(i);
10597a4820cSSimon Pilgrim       RawMask[i] = 0;
10697a4820cSSimon Pilgrim       continue;
10797a4820cSSimon Pilgrim     }
10897a4820cSSimon Pilgrim 
1090f5fb5f5SSimon Pilgrim     APInt EltBits = MaskBits.extractBits(MaskEltSizeInBits, BitOffset);
11097a4820cSSimon Pilgrim     RawMask[i] = EltBits.getZExtValue();
11197a4820cSSimon Pilgrim   }
11297a4820cSSimon Pilgrim 
11397a4820cSSimon Pilgrim   return true;
11497a4820cSSimon Pilgrim }
11597a4820cSSimon Pilgrim 
DecodePSHUFBMask(const Constant * C,unsigned Width,SmallVectorImpl<int> & ShuffleMask)116c8e183f9SCraig Topper void DecodePSHUFBMask(const Constant *C, unsigned Width,
117c8e183f9SCraig Topper                       SmallVectorImpl<int> &ShuffleMask) {
118c8e183f9SCraig Topper   assert((Width == 128 || Width == 256 || Width == 512) &&
119c8e183f9SCraig Topper          C->getType()->getPrimitiveSizeInBits() >= Width &&
120630dd6ffSSimon Pilgrim          "Unexpected vector size.");
12197a4820cSSimon Pilgrim 
12297a4820cSSimon Pilgrim   // The shuffle mask requires a byte vector.
12353e5a38dSCraig Topper   APInt UndefElts;
124e1be95c3SCraig Topper   SmallVector<uint64_t, 64> RawMask;
12597a4820cSSimon Pilgrim   if (!extractConstantMask(C, 8, UndefElts, RawMask))
12697a4820cSSimon Pilgrim     return;
12797a4820cSSimon Pilgrim 
128c8e183f9SCraig Topper   unsigned NumElts = Width / 8;
12997a4820cSSimon Pilgrim   assert((NumElts == 16 || NumElts == 32 || NumElts == 64) &&
13097a4820cSSimon Pilgrim          "Unexpected number of vector elements.");
13197a4820cSSimon Pilgrim 
13297a4820cSSimon Pilgrim   for (unsigned i = 0; i != NumElts; ++i) {
13397a4820cSSimon Pilgrim     if (UndefElts[i]) {
13497a4820cSSimon Pilgrim       ShuffleMask.push_back(SM_SentinelUndef);
13597a4820cSSimon Pilgrim       continue;
13697a4820cSSimon Pilgrim     }
13797a4820cSSimon Pilgrim 
13897a4820cSSimon Pilgrim     uint64_t Element = RawMask[i];
13969653af7SCraig Topper     // If the high bit (7) of the byte is set, the element is zeroed.
14069653af7SCraig Topper     if (Element & (1 << 7))
14169653af7SCraig Topper       ShuffleMask.push_back(SM_SentinelZero);
14269653af7SCraig Topper     else {
14397a4820cSSimon Pilgrim       // For AVX vectors with 32 bytes the base of the shuffle is the 16-byte
14497a4820cSSimon Pilgrim       // lane of the vector we're inside.
14597a4820cSSimon Pilgrim       unsigned Base = i & ~0xf;
14697a4820cSSimon Pilgrim 
14769653af7SCraig Topper       // Only the least significant 4 bits of the byte are used.
14869653af7SCraig Topper       int Index = Base + (Element & 0xf);
14969653af7SCraig Topper       ShuffleMask.push_back(Index);
15069653af7SCraig Topper     }
15169653af7SCraig Topper   }
15269653af7SCraig Topper }
15305e48b95SSimon Pilgrim 
DecodeVPERMILPMask(const Constant * C,unsigned ElSize,unsigned Width,SmallVectorImpl<int> & ShuffleMask)154c8e183f9SCraig Topper void DecodeVPERMILPMask(const Constant *C, unsigned ElSize, unsigned Width,
15569653af7SCraig Topper                         SmallVectorImpl<int> &ShuffleMask) {
156c8e183f9SCraig Topper   assert((Width == 128 || Width == 256 || Width == 512) &&
157c8e183f9SCraig Topper          C->getType()->getPrimitiveSizeInBits() >= Width &&
158630dd6ffSSimon Pilgrim          "Unexpected vector size.");
159630dd6ffSSimon Pilgrim   assert((ElSize == 32 || ElSize == 64) && "Unexpected vector element size.");
16097a4820cSSimon Pilgrim 
16197a4820cSSimon Pilgrim   // The shuffle mask requires elements the same size as the target.
16253e5a38dSCraig Topper   APInt UndefElts;
163e1be95c3SCraig Topper   SmallVector<uint64_t, 16> RawMask;
16497a4820cSSimon Pilgrim   if (!extractConstantMask(C, ElSize, UndefElts, RawMask))
16569653af7SCraig Topper     return;
16669653af7SCraig Topper 
167c8e183f9SCraig Topper   unsigned NumElts = Width / ElSize;
16897a4820cSSimon Pilgrim   unsigned NumEltsPerLane = 128 / ElSize;
16997a4820cSSimon Pilgrim   assert((NumElts == 2 || NumElts == 4 || NumElts == 8 || NumElts == 16) &&
17069653af7SCraig Topper          "Unexpected number of vector elements.");
17169653af7SCraig Topper 
17297a4820cSSimon Pilgrim   for (unsigned i = 0; i != NumElts; ++i) {
17397a4820cSSimon Pilgrim     if (UndefElts[i]) {
17469653af7SCraig Topper       ShuffleMask.push_back(SM_SentinelUndef);
17569653af7SCraig Topper       continue;
17669653af7SCraig Topper     }
17797a4820cSSimon Pilgrim 
17897a4820cSSimon Pilgrim     int Index = i & ~(NumEltsPerLane - 1);
17997a4820cSSimon Pilgrim     uint64_t Element = RawMask[i];
18069653af7SCraig Topper     if (ElSize == 64)
18169653af7SCraig Topper       Index += (Element >> 1) & 0x1;
18269653af7SCraig Topper     else
18369653af7SCraig Topper       Index += Element & 0x3;
18497a4820cSSimon Pilgrim 
18569653af7SCraig Topper     ShuffleMask.push_back(Index);
18669653af7SCraig Topper   }
18769653af7SCraig Topper }
18869653af7SCraig Topper 
DecodeVPERMIL2PMask(const Constant * C,unsigned M2Z,unsigned ElSize,unsigned Width,SmallVectorImpl<int> & ShuffleMask)1892ead861dSSimon Pilgrim void DecodeVPERMIL2PMask(const Constant *C, unsigned M2Z, unsigned ElSize,
190f5ad93d2SSimon Pilgrim                          unsigned Width, SmallVectorImpl<int> &ShuffleMask) {
1912ead861dSSimon Pilgrim   Type *MaskTy = C->getType();
1922ead861dSSimon Pilgrim   unsigned MaskTySize = MaskTy->getPrimitiveSizeInBits();
1933ace13adSDouglas Katzman   (void)MaskTySize;
194f5ad93d2SSimon Pilgrim   assert((MaskTySize == 128 || MaskTySize == 256) && Width >= MaskTySize &&
195f5ad93d2SSimon Pilgrim          "Unexpected vector size.");
19697a4820cSSimon Pilgrim 
19797a4820cSSimon Pilgrim   // The shuffle mask requires elements the same size as the target.
19853e5a38dSCraig Topper   APInt UndefElts;
19997a4820cSSimon Pilgrim   SmallVector<uint64_t, 8> RawMask;
20097a4820cSSimon Pilgrim   if (!extractConstantMask(C, ElSize, UndefElts, RawMask))
2012ead861dSSimon Pilgrim     return;
2022ead861dSSimon Pilgrim 
203c8e183f9SCraig Topper   unsigned NumElts = Width / ElSize;
20497a4820cSSimon Pilgrim   unsigned NumEltsPerLane = 128 / ElSize;
20597a4820cSSimon Pilgrim   assert((NumElts == 2 || NumElts == 4 || NumElts == 8) &&
2062ead861dSSimon Pilgrim          "Unexpected number of vector elements.");
2072ead861dSSimon Pilgrim 
20897a4820cSSimon Pilgrim   for (unsigned i = 0; i != NumElts; ++i) {
20997a4820cSSimon Pilgrim     if (UndefElts[i]) {
2102ead861dSSimon Pilgrim       ShuffleMask.push_back(SM_SentinelUndef);
2112ead861dSSimon Pilgrim       continue;
2122ead861dSSimon Pilgrim     }
2132ead861dSSimon Pilgrim 
2142ead861dSSimon Pilgrim     // VPERMIL2 Operation.
2152ead861dSSimon Pilgrim     // Bits[3] - Match Bit.
2162ead861dSSimon Pilgrim     // Bits[2:1] - (Per Lane) PD Shuffle Mask.
2172ead861dSSimon Pilgrim     // Bits[2:0] - (Per Lane) PS Shuffle Mask.
21897a4820cSSimon Pilgrim     uint64_t Selector = RawMask[i];
2194c0e94dcSChandler Carruth     unsigned MatchBit = (Selector >> 3) & 0x1;
2202ead861dSSimon Pilgrim 
2212ead861dSSimon Pilgrim     // M2Z[0:1]     MatchBit
2222ead861dSSimon Pilgrim     //   0Xb           X        Source selected by Selector index.
2232ead861dSSimon Pilgrim     //   10b           0        Source selected by Selector index.
2242ead861dSSimon Pilgrim     //   10b           1        Zero.
2252ead861dSSimon Pilgrim     //   11b           0        Zero.
2262ead861dSSimon Pilgrim     //   11b           1        Source selected by Selector index.
227306e270bSChandler Carruth     if ((M2Z & 0x2) != 0u && MatchBit != (M2Z & 0x1)) {
2282ead861dSSimon Pilgrim       ShuffleMask.push_back(SM_SentinelZero);
2292ead861dSSimon Pilgrim       continue;
2302ead861dSSimon Pilgrim     }
2312ead861dSSimon Pilgrim 
23297a4820cSSimon Pilgrim     int Index = i & ~(NumEltsPerLane - 1);
233163987a2SSimon Pilgrim     if (ElSize == 64)
234163987a2SSimon Pilgrim       Index += (Selector >> 1) & 0x1;
235163987a2SSimon Pilgrim     else
236163987a2SSimon Pilgrim       Index += Selector & 0x3;
2372ead861dSSimon Pilgrim 
2382ead861dSSimon Pilgrim     int Src = (Selector >> 2) & 0x1;
23997a4820cSSimon Pilgrim     Index += Src * NumElts;
2402ead861dSSimon Pilgrim     ShuffleMask.push_back(Index);
2412ead861dSSimon Pilgrim   }
2422ead861dSSimon Pilgrim }
2432ead861dSSimon Pilgrim 
DecodeVPPERMMask(const Constant * C,unsigned Width,SmallVectorImpl<int> & ShuffleMask)244c8e183f9SCraig Topper void DecodeVPPERMMask(const Constant *C, unsigned Width,
245c8e183f9SCraig Topper                       SmallVectorImpl<int> &ShuffleMask) {
246c8e183f9SCraig Topper   Type *MaskTy = C->getType();
247c8e183f9SCraig Topper   unsigned MaskTySize = MaskTy->getPrimitiveSizeInBits();
248c8e183f9SCraig Topper   (void)MaskTySize;
249c8e183f9SCraig Topper   assert(Width == 128 && Width >= MaskTySize && "Unexpected vector size.");
2501cc57127SSimon Pilgrim 
25197a4820cSSimon Pilgrim   // The shuffle mask requires a byte vector.
25253e5a38dSCraig Topper   APInt UndefElts;
253e1be95c3SCraig Topper   SmallVector<uint64_t, 16> RawMask;
25497a4820cSSimon Pilgrim   if (!extractConstantMask(C, 8, UndefElts, RawMask))
2551cc57127SSimon Pilgrim     return;
2561cc57127SSimon Pilgrim 
257c8e183f9SCraig Topper   unsigned NumElts = Width / 8;
25897a4820cSSimon Pilgrim   assert(NumElts == 16 && "Unexpected number of vector elements.");
2591cc57127SSimon Pilgrim 
26097a4820cSSimon Pilgrim   for (unsigned i = 0; i != NumElts; ++i) {
26197a4820cSSimon Pilgrim     if (UndefElts[i]) {
26297a4820cSSimon Pilgrim       ShuffleMask.push_back(SM_SentinelUndef);
2631cc57127SSimon Pilgrim       continue;
2641cc57127SSimon Pilgrim     }
2651cc57127SSimon Pilgrim 
2661cc57127SSimon Pilgrim     // VPPERM Operation
2671cc57127SSimon Pilgrim     // Bits[4:0] - Byte Index (0 - 31)
2681cc57127SSimon Pilgrim     // Bits[7:5] - Permute Operation
2691cc57127SSimon Pilgrim     //
2701cc57127SSimon Pilgrim     // Permute Operation:
2711cc57127SSimon Pilgrim     // 0 - Source byte (no logical operation).
2721cc57127SSimon Pilgrim     // 1 - Invert source byte.
2731cc57127SSimon Pilgrim     // 2 - Bit reverse of source byte.
2741cc57127SSimon Pilgrim     // 3 - Bit reverse of inverted source byte.
2751cc57127SSimon Pilgrim     // 4 - 00h (zero - fill).
2761cc57127SSimon Pilgrim     // 5 - FFh (ones - fill).
2771cc57127SSimon Pilgrim     // 6 - Most significant bit of source byte replicated in all bit positions.
27897a4820cSSimon Pilgrim     // 7 - Invert most significant bit of source byte and replicate in all bit
27997a4820cSSimon Pilgrim     // positions.
28097a4820cSSimon Pilgrim     uint64_t Element = RawMask[i];
28197a4820cSSimon Pilgrim     uint64_t Index = Element & 0x1F;
28297a4820cSSimon Pilgrim     uint64_t PermuteOp = (Element >> 5) & 0x7;
2831cc57127SSimon Pilgrim 
2841cc57127SSimon Pilgrim     if (PermuteOp == 4) {
2851cc57127SSimon Pilgrim       ShuffleMask.push_back(SM_SentinelZero);
2861cc57127SSimon Pilgrim       continue;
2871cc57127SSimon Pilgrim     }
2881cc57127SSimon Pilgrim     if (PermuteOp != 0) {
2891cc57127SSimon Pilgrim       ShuffleMask.clear();
2901cc57127SSimon Pilgrim       return;
2911cc57127SSimon Pilgrim     }
29297a4820cSSimon Pilgrim     ShuffleMask.push_back((int)Index);
2931cc57127SSimon Pilgrim   }
2941cc57127SSimon Pilgrim }
2951cc57127SSimon Pilgrim 
2960793b456SSimon Pilgrim } // namespace llvm
297