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