6bb058298b
Fixes Node.js builds with GCC 8. Change-Id: I3db574b48992f36ba42dec5c21d5c4b55dd7aa19 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2780297 Auto-Submit: Michaël Zasso <mic.besace@gmail.com> Commit-Queue: Jakob Kummerow <jkummerow@chromium.org> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> Cr-Commit-Position: refs/heads/master@{#73614}
175 lines
5.2 KiB
C++
175 lines
5.2 KiB
C++
// Copyright 2020 the V8 project authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "src/wasm/simd-shuffle.h"
|
|
|
|
#include <algorithm>
|
|
|
|
#include "src/common/globals.h"
|
|
|
|
namespace v8 {
|
|
namespace internal {
|
|
namespace wasm {
|
|
|
|
void SimdShuffle::CanonicalizeShuffle(bool inputs_equal, uint8_t* shuffle,
|
|
bool* needs_swap, bool* is_swizzle) {
|
|
*needs_swap = false;
|
|
// Inputs equal, then it's a swizzle.
|
|
if (inputs_equal) {
|
|
*is_swizzle = true;
|
|
} else {
|
|
// Inputs are distinct; check that both are required.
|
|
bool src0_is_used = false;
|
|
bool src1_is_used = false;
|
|
for (int i = 0; i < kSimd128Size; ++i) {
|
|
if (shuffle[i] < kSimd128Size) {
|
|
src0_is_used = true;
|
|
} else {
|
|
src1_is_used = true;
|
|
}
|
|
}
|
|
if (src0_is_used && !src1_is_used) {
|
|
*is_swizzle = true;
|
|
} else if (src1_is_used && !src0_is_used) {
|
|
*needs_swap = true;
|
|
*is_swizzle = true;
|
|
} else {
|
|
*is_swizzle = false;
|
|
// Canonicalize general 2 input shuffles so that the first input lanes are
|
|
// encountered first. This makes architectural shuffle pattern matching
|
|
// easier, since we only need to consider 1 input ordering instead of 2.
|
|
if (shuffle[0] >= kSimd128Size) {
|
|
// The second operand is used first. Swap inputs and adjust the shuffle.
|
|
*needs_swap = true;
|
|
for (int i = 0; i < kSimd128Size; ++i) {
|
|
shuffle[i] ^= kSimd128Size;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (*is_swizzle) {
|
|
for (int i = 0; i < kSimd128Size; ++i) shuffle[i] &= kSimd128Size - 1;
|
|
}
|
|
}
|
|
|
|
bool SimdShuffle::TryMatchIdentity(const uint8_t* shuffle) {
|
|
for (int i = 0; i < kSimd128Size; ++i) {
|
|
if (shuffle[i] != i) return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool SimdShuffle::TryMatch32x4Rotate(const uint8_t* shuffle,
|
|
uint8_t* shuffle32x4, bool is_swizzle) {
|
|
uint8_t offset;
|
|
bool is_concat = TryMatchConcat(shuffle, &offset);
|
|
DCHECK_NE(offset, 0); // 0 is identity, it should not be matched.
|
|
// Since we already have a concat shuffle, we know that the indices goes from:
|
|
// [ offset, ..., 15, 0, ... ], it suffices to check that the offset points
|
|
// to the low byte of a 32x4 element.
|
|
if (!is_concat || !is_swizzle || offset % 4 != 0) {
|
|
return false;
|
|
}
|
|
|
|
uint8_t offset_32 = offset / 4;
|
|
for (int i = 0; i < 4; i++) {
|
|
shuffle32x4[i] = (offset_32 + i) % 4;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool SimdShuffle::TryMatch32x4Shuffle(const uint8_t* shuffle,
|
|
uint8_t* shuffle32x4) {
|
|
for (int i = 0; i < 4; ++i) {
|
|
if (shuffle[i * 4] % 4 != 0) return false;
|
|
for (int j = 1; j < 4; ++j) {
|
|
if (shuffle[i * 4 + j] - shuffle[i * 4 + j - 1] != 1) return false;
|
|
}
|
|
shuffle32x4[i] = shuffle[i * 4] / 4;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool SimdShuffle::TryMatch16x8Shuffle(const uint8_t* shuffle,
|
|
uint8_t* shuffle16x8) {
|
|
for (int i = 0; i < 8; ++i) {
|
|
if (shuffle[i * 2] % 2 != 0) return false;
|
|
for (int j = 1; j < 2; ++j) {
|
|
if (shuffle[i * 2 + j] - shuffle[i * 2 + j - 1] != 1) return false;
|
|
}
|
|
shuffle16x8[i] = shuffle[i * 2] / 2;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool SimdShuffle::TryMatchConcat(const uint8_t* shuffle, uint8_t* offset) {
|
|
// Don't match the identity shuffle (e.g. [0 1 2 ... 15]).
|
|
uint8_t start = shuffle[0];
|
|
if (start == 0) return false;
|
|
DCHECK_GT(kSimd128Size, start); // The shuffle should be canonicalized.
|
|
// A concatenation is a series of consecutive indices, with at most one jump
|
|
// in the middle from the last lane to the first.
|
|
for (int i = 1; i < kSimd128Size; ++i) {
|
|
if ((shuffle[i]) != ((shuffle[i - 1] + 1))) {
|
|
if (shuffle[i - 1] != 15) return false;
|
|
if (shuffle[i] % kSimd128Size != 0) return false;
|
|
}
|
|
}
|
|
*offset = start;
|
|
return true;
|
|
}
|
|
|
|
bool SimdShuffle::TryMatchBlend(const uint8_t* shuffle) {
|
|
for (int i = 0; i < 16; ++i) {
|
|
if ((shuffle[i] & 0xF) != i) return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
uint8_t SimdShuffle::PackShuffle4(uint8_t* shuffle) {
|
|
return (shuffle[0] & 3) | ((shuffle[1] & 3) << 2) | ((shuffle[2] & 3) << 4) |
|
|
((shuffle[3] & 3) << 6);
|
|
}
|
|
|
|
uint8_t SimdShuffle::PackBlend8(const uint8_t* shuffle16x8) {
|
|
int8_t result = 0;
|
|
for (int i = 0; i < 8; ++i) {
|
|
result |= (shuffle16x8[i] >= 8 ? 1 : 0) << i;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
uint8_t SimdShuffle::PackBlend4(const uint8_t* shuffle32x4) {
|
|
int8_t result = 0;
|
|
for (int i = 0; i < 4; ++i) {
|
|
result |= (shuffle32x4[i] >= 4 ? 0x3 : 0) << (i * 2);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
int32_t SimdShuffle::Pack4Lanes(const uint8_t* shuffle) {
|
|
int32_t result = 0;
|
|
for (int i = 3; i >= 0; --i) {
|
|
result <<= 8;
|
|
result |= shuffle[i];
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void SimdShuffle::Pack16Lanes(uint32_t* dst, const uint8_t* shuffle) {
|
|
for (int i = 0; i < 4; i++) {
|
|
dst[i] = wasm::SimdShuffle::Pack4Lanes(shuffle + (i * 4));
|
|
}
|
|
}
|
|
|
|
bool SimdSwizzle::AllInRangeOrTopBitSet(
|
|
std::array<uint8_t, kSimd128Size> shuffle) {
|
|
return std::all_of(shuffle.begin(), shuffle.end(),
|
|
[](auto i) { return (i < kSimd128Size) || (i & 0x80); });
|
|
}
|
|
|
|
} // namespace wasm
|
|
} // namespace internal
|
|
} // namespace v8
|