• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/wasm/simd-shuffle.h"
6 
7 #include "src/common/globals.h"
8 
9 namespace v8 {
10 namespace internal {
11 namespace wasm {
12 
CanonicalizeShuffle(bool inputs_equal,uint8_t * shuffle,bool * needs_swap,bool * is_swizzle)13 void SimdShuffle::CanonicalizeShuffle(bool inputs_equal, uint8_t* shuffle,
14                                       bool* needs_swap, bool* is_swizzle) {
15   *needs_swap = false;
16   // Inputs equal, then it's a swizzle.
17   if (inputs_equal) {
18     *is_swizzle = true;
19   } else {
20     // Inputs are distinct; check that both are required.
21     bool src0_is_used = false;
22     bool src1_is_used = false;
23     for (int i = 0; i < kSimd128Size; ++i) {
24       if (shuffle[i] < kSimd128Size) {
25         src0_is_used = true;
26       } else {
27         src1_is_used = true;
28       }
29     }
30     if (src0_is_used && !src1_is_used) {
31       *is_swizzle = true;
32     } else if (src1_is_used && !src0_is_used) {
33       *needs_swap = true;
34       *is_swizzle = true;
35     } else {
36       *is_swizzle = false;
37       // Canonicalize general 2 input shuffles so that the first input lanes are
38       // encountered first. This makes architectural shuffle pattern matching
39       // easier, since we only need to consider 1 input ordering instead of 2.
40       if (shuffle[0] >= kSimd128Size) {
41         // The second operand is used first. Swap inputs and adjust the shuffle.
42         *needs_swap = true;
43         for (int i = 0; i < kSimd128Size; ++i) {
44           shuffle[i] ^= kSimd128Size;
45         }
46       }
47     }
48   }
49   if (*is_swizzle) {
50     for (int i = 0; i < kSimd128Size; ++i) shuffle[i] &= kSimd128Size - 1;
51   }
52 }
53 
TryMatchIdentity(const uint8_t * shuffle)54 bool SimdShuffle::TryMatchIdentity(const uint8_t* shuffle) {
55   for (int i = 0; i < kSimd128Size; ++i) {
56     if (shuffle[i] != i) return false;
57   }
58   return true;
59 }
60 
TryMatch32x4Shuffle(const uint8_t * shuffle,uint8_t * shuffle32x4)61 bool SimdShuffle::TryMatch32x4Shuffle(const uint8_t* shuffle,
62                                       uint8_t* shuffle32x4) {
63   for (int i = 0; i < 4; ++i) {
64     if (shuffle[i * 4] % 4 != 0) return false;
65     for (int j = 1; j < 4; ++j) {
66       if (shuffle[i * 4 + j] - shuffle[i * 4 + j - 1] != 1) return false;
67     }
68     shuffle32x4[i] = shuffle[i * 4] / 4;
69   }
70   return true;
71 }
72 
TryMatch16x8Shuffle(const uint8_t * shuffle,uint8_t * shuffle16x8)73 bool SimdShuffle::TryMatch16x8Shuffle(const uint8_t* shuffle,
74                                       uint8_t* shuffle16x8) {
75   for (int i = 0; i < 8; ++i) {
76     if (shuffle[i * 2] % 2 != 0) return false;
77     for (int j = 1; j < 2; ++j) {
78       if (shuffle[i * 2 + j] - shuffle[i * 2 + j - 1] != 1) return false;
79     }
80     shuffle16x8[i] = shuffle[i * 2] / 2;
81   }
82   return true;
83 }
84 
TryMatchConcat(const uint8_t * shuffle,uint8_t * offset)85 bool SimdShuffle::TryMatchConcat(const uint8_t* shuffle, uint8_t* offset) {
86   // Don't match the identity shuffle (e.g. [0 1 2 ... 15]).
87   uint8_t start = shuffle[0];
88   if (start == 0) return false;
89   DCHECK_GT(kSimd128Size, start);  // The shuffle should be canonicalized.
90   // A concatenation is a series of consecutive indices, with at most one jump
91   // in the middle from the last lane to the first.
92   for (int i = 1; i < kSimd128Size; ++i) {
93     if ((shuffle[i]) != ((shuffle[i - 1] + 1))) {
94       if (shuffle[i - 1] != 15) return false;
95       if (shuffle[i] % kSimd128Size != 0) return false;
96     }
97   }
98   *offset = start;
99   return true;
100 }
101 
TryMatchBlend(const uint8_t * shuffle)102 bool SimdShuffle::TryMatchBlend(const uint8_t* shuffle) {
103   for (int i = 0; i < 16; ++i) {
104     if ((shuffle[i] & 0xF) != i) return false;
105   }
106   return true;
107 }
108 
PackShuffle4(uint8_t * shuffle)109 uint8_t SimdShuffle::PackShuffle4(uint8_t* shuffle) {
110   return (shuffle[0] & 3) | ((shuffle[1] & 3) << 2) | ((shuffle[2] & 3) << 4) |
111          ((shuffle[3] & 3) << 6);
112 }
113 
PackBlend8(const uint8_t * shuffle16x8)114 uint8_t SimdShuffle::PackBlend8(const uint8_t* shuffle16x8) {
115   int8_t result = 0;
116   for (int i = 0; i < 8; ++i) {
117     result |= (shuffle16x8[i] >= 8 ? 1 : 0) << i;
118   }
119   return result;
120 }
121 
PackBlend4(const uint8_t * shuffle32x4)122 uint8_t SimdShuffle::PackBlend4(const uint8_t* shuffle32x4) {
123   int8_t result = 0;
124   for (int i = 0; i < 4; ++i) {
125     result |= (shuffle32x4[i] >= 4 ? 0x3 : 0) << (i * 2);
126   }
127   return result;
128 }
129 
Pack4Lanes(const uint8_t * shuffle)130 int32_t SimdShuffle::Pack4Lanes(const uint8_t* shuffle) {
131   int32_t result = 0;
132   for (int i = 3; i >= 0; --i) {
133     result <<= 8;
134     result |= shuffle[i];
135   }
136   return result;
137 }
138 
Pack16Lanes(uint32_t * dst,const uint8_t * shuffle)139 void SimdShuffle::Pack16Lanes(uint32_t* dst, const uint8_t* shuffle) {
140   for (int i = 0; i < 4; i++) {
141     dst[i] = wasm::SimdShuffle::Pack4Lanes(shuffle + (i * 4));
142   }
143 }
144 
145 }  // namespace wasm
146 }  // namespace internal
147 }  // namespace v8
148