[wasm-simd] New macro to build using vector of bytes

Introduces a new macro BUILD_V (v is for vector) that pushes bytes into
a vector (instead of directly in an array initializer, see BUILD). This
has the positive effect of being able to handle opcodes of multiple
bytes (e.g. SIMD opcodes bigger that 0xfd80). Because of this "API"
change, our helper macros in test-run-wasm-simd.cc and wasm-run-utils.h
need to change too. So, we introduce new macros (suffixed by _V), that
will call the appropriate lambdas defined in BUILD_V, that knows how to
push bytes into the vector, and also can handle multi-byte opcodes.

This design has a bit of duplication and ugliness, but was chosen to
reduce the impact of existing tests. No restructuring of test code is
required, we only need to add suffix _V.

Note that we do not have multi-byte opcodes yet (in wasm-opcodes.h),
this change will be breaking, and requires all the tests to be updated
to use _V macros first.

Bug: v8:10258
Change-Id: I86638a548fe2f9714c1cfb3bd691fb7b49bfd652
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2107650
Commit-Queue: Zhi An Ng <zhin@chromium.org>
Reviewed-by: Clemens Backes <clemensb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#66812}
This commit is contained in:
Ng Zhi An 2020-03-20 09:38:37 -07:00 committed by Commit Bot
parent 6c1e09aebe
commit 1e40c682e9
3 changed files with 73 additions and 3 deletions

View File

@ -409,6 +409,9 @@ bool ExpectFused(ExecutionTier tier) {
WASM_RETURN1(WASM_ZERO))
#define TO_BYTE(val) static_cast<byte>(val)
// TODO(v8:10258): We have support for emitting multi-byte opcodes now, so this
// can change to simply, op, once the decoder is fixed to decode multi byte
// opcodes.
#define WASM_SIMD_OP(op) kSimdPrefix, TO_BYTE(op)
#define WASM_SIMD_SPLAT(Type, ...) __VA_ARGS__, WASM_SIMD_OP(kExpr##Type##Splat)
#define WASM_SIMD_UNOP(op, x) x, WASM_SIMD_OP(op)
@ -545,7 +548,7 @@ WASM_SIMD_TEST(S128Globals) {
// Set up a global to hold input and output vectors.
int32_t* g0 = r.builder().AddGlobal<int32_t>(kWasmS128);
int32_t* g1 = r.builder().AddGlobal<int32_t>(kWasmS128);
BUILD(r, WASM_SET_GLOBAL(1, WASM_GET_GLOBAL(0)), WASM_ONE);
BUILD_V(r, WASM_SET_GLOBAL(1, WASM_GET_GLOBAL(0)), WASM_ONE);
FOR_INT32_INPUTS(x) {
for (int i = 0; i < 4; i++) {
@ -937,8 +940,8 @@ WASM_SIMD_TEST_NO_LOWERING(I64x2Splat) {
// Set up a global to hold output vector.
int64_t* g = r.builder().AddGlobal<int64_t>(kWasmS128);
byte param1 = 0;
BUILD(r, WASM_SET_GLOBAL(0, WASM_SIMD_I64x2_SPLAT(WASM_GET_LOCAL(param1))),
WASM_ONE);
BUILD_V(r, WASM_SET_GLOBAL(0, WASM_SIMD_I64x2_SPLAT(WASM_GET_LOCAL(param1))),
WASM_ONE);
FOR_INT64_INPUTS(x) {
r.Call(x);

View File

@ -8,14 +8,45 @@
#include "src/diagnostics/code-tracer.h"
#include "src/heap/heap-inl.h"
#include "src/wasm/graph-builder-interface.h"
#include "src/wasm/leb-helper.h"
#include "src/wasm/module-compiler.h"
#include "src/wasm/wasm-import-wrapper-cache.h"
#include "src/wasm/wasm-objects-inl.h"
#include "src/wasm/wasm-opcodes.h"
namespace v8 {
namespace internal {
namespace wasm {
template <>
void AppendSingle(std::vector<byte>* code, WasmOpcode op) {
// We do not yet have opcodes that take up more than 2 byte (decoded). But if
// that changes, this will need to be updated.
DCHECK_EQ(0, op >> 16);
byte prefix = (op >> 8) & 0xff;
byte opcode = op & 0xff;
if (!prefix) {
code->push_back(opcode);
return;
}
// Ensure the prefix is really one of the supported prefixed opcodes.
DCHECK(WasmOpcodes::IsPrefixOpcode(static_cast<WasmOpcode>(prefix)));
code->push_back(prefix);
// Decoded opcodes fit in a byte (0x00-0xff).
DCHECK_LE(LEBHelper::sizeof_u32v(opcode), 2);
// Therefore, the encoding needs max 2 bytes.
uint8_t encoded[2];
uint8_t* d = encoded;
// d is updated to after the last uint8_t written.
LEBHelper::write_u32v(&d, opcode);
for (uint8_t* p = encoded; p < d; p++) {
code->push_back(*p);
}
}
TestingModuleBuilder::TestingModuleBuilder(
Zone* zone, ManuallyImportedJSFunction* maybe_import, ExecutionTier tier,
RuntimeExceptionSupport exception_support, LowerSimd lower_simd)

View File

@ -75,6 +75,42 @@ using compiler::Node;
r.Build(code, code + arraysize(code)); \
} while (false)
template <typename T>
void AppendSingle(std::vector<byte>* code, T t) {
static_assert(std::is_integral<T>::value,
"Special types need specializations");
code->push_back(t);
}
// Specialized for WasmOpcode.
template <>
void AppendSingle<WasmOpcode>(std::vector<byte>* code, WasmOpcode op);
template <typename... T>
void Append(std::vector<byte>* code, T... ts) {
static_assert(sizeof...(ts) == 0, "Base case for appending bytes to code.");
}
template <typename First, typename... Rest>
void Append(std::vector<byte>* code, First first, Rest... rest) {
AppendSingle(code, first);
Append(code, rest...);
}
// Like BUILD but pushes code bytes into a std::vector instead of an array
// initializer. This is useful for opcodes (like SIMD), that are LEB128
// (variable-sized). We use recursive template instantiations with variadic
// template arguments, so that the Append calls can handle either bytes or
// opcodes. AppendSingle is specialized for WasmOpcode, and appends multiple
// bytes. This allows existing callers to swap out the BUILD macro for BUILD_V
// macro without changes. Also see https://crbug.com/v8/10258.
#define BUILD_V(r, ...) \
do { \
std::vector<byte> code; \
Append(&code, __VA_ARGS__); \
r.Build(code.data(), code.data() + code.size()); \
} while (false)
// For tests that must manually import a JSFunction with source code.
struct ManuallyImportedJSFunction {
const FunctionSig* sig;