Commit d34178fd authored by Andreas Haas's avatar Andreas Haas Committed by Commit Bot

[wasm][anyref] Introduce the select_with_type instruction

The instruction is the same as the existing {select} instruction with
type. Both inputs must be in a sub-type relationship with the type
specified in the type instruction.

R=clemensh@chromium.org

Bug: v8:7581
Change-Id: Ibead6cd0253210828c8114336ea0942e6cbd6126
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1631413
Commit-Queue: Andreas Haas <ahaas@chromium.org>
Reviewed-by: 's avatarClemens Hammacher <clemensh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#61886}
parent f5ab7d38
...@@ -206,6 +206,68 @@ struct GlobalIndexImmediate { ...@@ -206,6 +206,68 @@ struct GlobalIndexImmediate {
} }
}; };
namespace function_body_decoder {
// Decode a byte representing a local type. Return {false} if the encoded
// byte was invalid or the start of a type index.
inline bool decode_local_type(uint8_t val, ValueType* result) {
switch (static_cast<ValueTypeCode>(val)) {
case kLocalVoid:
*result = kWasmStmt;
return true;
case kLocalI32:
*result = kWasmI32;
return true;
case kLocalI64:
*result = kWasmI64;
return true;
case kLocalF32:
*result = kWasmF32;
return true;
case kLocalF64:
*result = kWasmF64;
return true;
case kLocalS128:
*result = kWasmS128;
return true;
case kLocalAnyFunc:
*result = kWasmAnyFunc;
return true;
case kLocalAnyRef:
*result = kWasmAnyRef;
return true;
case kLocalExceptRef:
*result = kWasmExceptRef;
return true;
default:
*result = kWasmVar;
return false;
}
}
} // namespace function_body_decoder
template <Decoder::ValidateFlag validate>
struct SelectTypeImmediate {
uint32_t length;
ValueType type;
inline SelectTypeImmediate(Decoder* decoder, const byte* pc) {
uint8_t num_types =
decoder->read_u32v<validate>(pc + 1, &length, "number of select types");
if (!VALIDATE(num_types == 1)) {
decoder->error(
pc + 1, "Invalid number of types. Select accepts exactly one type");
return;
}
uint8_t val = decoder->read_u8<validate>(pc + length + 1, "select type");
length++;
if (!function_body_decoder::decode_local_type(val, &type) ||
type == kWasmStmt) {
decoder->error(pc + 1, "invalid select type");
return;
}
}
};
template <Decoder::ValidateFlag validate> template <Decoder::ValidateFlag validate>
struct BlockTypeImmediate { struct BlockTypeImmediate {
uint32_t length = 1; uint32_t length = 1;
...@@ -216,7 +278,7 @@ struct BlockTypeImmediate { ...@@ -216,7 +278,7 @@ struct BlockTypeImmediate {
inline BlockTypeImmediate(const WasmFeatures& enabled, Decoder* decoder, inline BlockTypeImmediate(const WasmFeatures& enabled, Decoder* decoder,
const byte* pc) { const byte* pc) {
uint8_t val = decoder->read_u8<validate>(pc + 1, "block type"); uint8_t val = decoder->read_u8<validate>(pc + 1, "block type");
if (!decode_local_type(val, &type)) { if (!function_body_decoder::decode_local_type(val, &type)) {
// Handle multi-value blocks. // Handle multi-value blocks.
if (!VALIDATE(enabled.mv)) { if (!VALIDATE(enabled.mv)) {
decoder->error(pc + 1, "invalid block type"); decoder->error(pc + 1, "invalid block type");
...@@ -233,43 +295,6 @@ struct BlockTypeImmediate { ...@@ -233,43 +295,6 @@ struct BlockTypeImmediate {
} }
} }
// Decode a byte representing a local type. Return {false} if the encoded
// byte was invalid or the start of a type index.
inline bool decode_local_type(uint8_t val, ValueType* result) {
switch (static_cast<ValueTypeCode>(val)) {
case kLocalVoid:
*result = kWasmStmt;
return true;
case kLocalI32:
*result = kWasmI32;
return true;
case kLocalI64:
*result = kWasmI64;
return true;
case kLocalF32:
*result = kWasmF32;
return true;
case kLocalF64:
*result = kWasmF64;
return true;
case kLocalS128:
*result = kWasmS128;
return true;
case kLocalAnyFunc:
*result = kWasmAnyFunc;
return true;
case kLocalAnyRef:
*result = kWasmAnyRef;
return true;
case kLocalExceptRef:
*result = kWasmExceptRef;
return true;
default:
*result = kWasmVar;
return false;
}
}
uint32_t in_arity() const { uint32_t in_arity() const {
if (type != kWasmVar) return 0; if (type != kWasmVar) return 0;
return static_cast<uint32_t>(sig->parameter_count()); return static_cast<uint32_t>(sig->parameter_count());
...@@ -1253,6 +1278,10 @@ class WasmDecoder : public Decoder { ...@@ -1253,6 +1278,10 @@ class WasmDecoder : public Decoder {
LocalIndexImmediate<validate> imm(decoder, pc); LocalIndexImmediate<validate> imm(decoder, pc);
return 1 + imm.length; return 1 + imm.length;
} }
case kExprSelectWithType: {
SelectTypeImmediate<validate> imm(decoder, pc);
return 1 + imm.length;
}
case kExprBrTable: { case kExprBrTable: {
BranchTableImmediate<validate> imm(decoder, pc); BranchTableImmediate<validate> imm(decoder, pc);
BranchTableIterator<validate> iterator(decoder, imm); BranchTableIterator<validate> iterator(decoder, imm);
...@@ -1397,6 +1426,7 @@ class WasmDecoder : public Decoder { ...@@ -1397,6 +1426,7 @@ class WasmDecoder : public Decoder {
// clang-format off // clang-format off
switch (opcode) { switch (opcode) {
case kExprSelect: case kExprSelect:
case kExprSelectWithType:
return {3, 1}; return {3, 1};
case kExprSetTable: case kExprSetTable:
FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE) FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE)
...@@ -1895,10 +1925,28 @@ class WasmFullDecoder : public WasmDecoder<validate> { ...@@ -1895,10 +1925,28 @@ class WasmFullDecoder : public WasmDecoder<validate> {
auto cond = Pop(2, kWasmI32); auto cond = Pop(2, kWasmI32);
auto fval = Pop(); auto fval = Pop();
auto tval = Pop(0, fval.type); auto tval = Pop(0, fval.type);
auto* result = Push(tval.type == kWasmVar ? fval.type : tval.type); ValueType type = tval.type == kWasmVar ? fval.type : tval.type;
if (ValueTypes::IsSubType(kWasmAnyRef, type)) {
this->error(
"select without type is only valid for value type inputs");
break;
}
auto* result = Push(type);
CALL_INTERFACE_IF_REACHABLE(Select, cond, fval, tval, result); CALL_INTERFACE_IF_REACHABLE(Select, cond, fval, tval, result);
break; break;
} }
case kExprSelectWithType: {
CHECK_PROTOTYPE_OPCODE(anyref);
SelectTypeImmediate<validate> imm(this, this->pc_);
if (this->failed()) break;
auto cond = Pop(2, kWasmI32);
auto fval = Pop(1, imm.type);
auto tval = Pop(0, imm.type);
auto* result = Push(imm.type);
CALL_INTERFACE_IF_REACHABLE(Select, cond, fval, tval, result);
len = 1 + imm.length;
break;
}
case kExprBr: { case kExprBr: {
BranchDepthImmediate<validate> imm(this, this->pc_); BranchDepthImmediate<validate> imm(this, this->pc_);
if (!this->Validate(this->pc_, imm, control_.size())) break; if (!this->Validate(this->pc_, imm, control_.size())) break;
......
...@@ -2837,6 +2837,11 @@ class ThreadImpl { ...@@ -2837,6 +2837,11 @@ class ThreadImpl {
} }
break; break;
} }
case kExprSelectWithType: {
SelectTypeImmediate<Decoder::kNoValidate> imm(&decoder, code->at(pc));
len = 1 + imm.length;
V8_FALLTHROUGH;
}
case kExprSelect: { case kExprSelect: {
WasmValue cond = Pop(); WasmValue cond = Pop();
WasmValue fval = Pop(); WasmValue fval = Pop();
......
...@@ -142,6 +142,7 @@ const char* WasmOpcodes::OpcodeName(WasmOpcode opcode) { ...@@ -142,6 +142,7 @@ const char* WasmOpcodes::OpcodeName(WasmOpcode opcode) {
CASE_OP(ReturnCallIndirect, "return_call_indirect") CASE_OP(ReturnCallIndirect, "return_call_indirect")
CASE_OP(Drop, "drop") CASE_OP(Drop, "drop")
CASE_OP(Select, "select") CASE_OP(Select, "select")
CASE_OP(SelectWithType, "select")
CASE_OP(GetLocal, "local.get") CASE_OP(GetLocal, "local.get")
CASE_OP(SetLocal, "local.set") CASE_OP(SetLocal, "local.set")
CASE_OP(TeeLocal, "local.tee") CASE_OP(TeeLocal, "local.tee")
......
...@@ -45,6 +45,7 @@ bool IsJSCompatibleSignature(const FunctionSig* sig, bool hasBigIntFeature); ...@@ -45,6 +45,7 @@ bool IsJSCompatibleSignature(const FunctionSig* sig, bool hasBigIntFeature);
V(ReturnCallIndirect, 0x13, _) \ V(ReturnCallIndirect, 0x13, _) \
V(Drop, 0x1a, _) \ V(Drop, 0x1a, _) \
V(Select, 0x1b, _) \ V(Select, 0x1b, _) \
V(SelectWithType, 0x1c, _) \
V(GetLocal, 0x20, _) \ V(GetLocal, 0x20, _) \
V(SetLocal, 0x21, _) \ V(SetLocal, 0x21, _) \
V(TeeLocal, 0x22, _) \ V(TeeLocal, 0x22, _) \
......
...@@ -752,12 +752,19 @@ WASM_EXEC_TEST(Return_F64) { ...@@ -752,12 +752,19 @@ WASM_EXEC_TEST(Return_F64) {
WASM_EXEC_TEST(Select_float_parameters) { WASM_EXEC_TEST(Select_float_parameters) {
WasmRunner<float, float, float, int32_t> r(execution_tier); WasmRunner<float, float, float, int32_t> r(execution_tier);
// return select(11, 22, a);
BUILD(r, BUILD(r,
WASM_SELECT(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1), WASM_GET_LOCAL(2))); WASM_SELECT(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1), WASM_GET_LOCAL(2)));
CHECK_FLOAT_EQ(2.0f, r.Call(2.0f, 1.0f, 1)); CHECK_FLOAT_EQ(2.0f, r.Call(2.0f, 1.0f, 1));
} }
WASM_EXEC_TEST(SelectWithType_float_parameters) {
EXPERIMENTAL_FLAG_SCOPE(anyref);
WasmRunner<float, float, float, int32_t> r(execution_tier);
BUILD(r,
WASM_SELECT_F(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1), WASM_GET_LOCAL(2)));
CHECK_FLOAT_EQ(2.0f, r.Call(2.0f, 1.0f, 1));
}
WASM_EXEC_TEST(Select) { WASM_EXEC_TEST(Select) {
WasmRunner<int32_t, int32_t> r(execution_tier); WasmRunner<int32_t, int32_t> r(execution_tier);
// return select(11, 22, a); // return select(11, 22, a);
...@@ -768,6 +775,17 @@ WASM_EXEC_TEST(Select) { ...@@ -768,6 +775,17 @@ WASM_EXEC_TEST(Select) {
} }
} }
WASM_EXEC_TEST(SelectWithType) {
EXPERIMENTAL_FLAG_SCOPE(anyref);
WasmRunner<int32_t, int32_t> r(execution_tier);
// return select(11, 22, a);
BUILD(r, WASM_SELECT_I(WASM_I32V_1(11), WASM_I32V_1(22), WASM_GET_LOCAL(0)));
FOR_INT32_INPUTS(i) {
int32_t expected = i ? 11 : 22;
CHECK_EQ(expected, r.Call(i));
}
}
WASM_EXEC_TEST(Select_strict1) { WASM_EXEC_TEST(Select_strict1) {
WasmRunner<int32_t, int32_t> r(execution_tier); WasmRunner<int32_t, int32_t> r(execution_tier);
// select(a=0, a=1, a=2); return a // select(a=0, a=1, a=2); return a
...@@ -778,6 +796,18 @@ WASM_EXEC_TEST(Select_strict1) { ...@@ -778,6 +796,18 @@ WASM_EXEC_TEST(Select_strict1) {
FOR_INT32_INPUTS(i) { CHECK_EQ(2, r.Call(i)); } FOR_INT32_INPUTS(i) { CHECK_EQ(2, r.Call(i)); }
} }
WASM_EXEC_TEST(SelectWithType_strict1) {
EXPERIMENTAL_FLAG_SCOPE(anyref);
WasmRunner<int32_t, int32_t> r(execution_tier);
// select(a=0, a=1, a=2); return a
BUILD(r,
WASM_SELECT_I(WASM_TEE_LOCAL(0, WASM_ZERO),
WASM_TEE_LOCAL(0, WASM_I32V_1(1)),
WASM_TEE_LOCAL(0, WASM_I32V_1(2))),
WASM_DROP, WASM_GET_LOCAL(0));
FOR_INT32_INPUTS(i) { CHECK_EQ(2, r.Call(i)); }
}
WASM_EXEC_TEST(Select_strict2) { WASM_EXEC_TEST(Select_strict2) {
WasmRunner<int32_t, int32_t> r(execution_tier); WasmRunner<int32_t, int32_t> r(execution_tier);
r.AllocateLocal(kWasmI32); r.AllocateLocal(kWasmI32);
...@@ -791,6 +821,20 @@ WASM_EXEC_TEST(Select_strict2) { ...@@ -791,6 +821,20 @@ WASM_EXEC_TEST(Select_strict2) {
} }
} }
WASM_EXEC_TEST(SelectWithType_strict2) {
EXPERIMENTAL_FLAG_SCOPE(anyref);
WasmRunner<int32_t, int32_t> r(execution_tier);
r.AllocateLocal(kWasmI32);
r.AllocateLocal(kWasmI32);
// select(b=5, c=6, a)
BUILD(r, WASM_SELECT_I(WASM_TEE_LOCAL(1, WASM_I32V_1(5)),
WASM_TEE_LOCAL(2, WASM_I32V_1(6)), WASM_GET_LOCAL(0)));
FOR_INT32_INPUTS(i) {
int32_t expected = i ? 5 : 6;
CHECK_EQ(expected, r.Call(i));
}
}
WASM_EXEC_TEST(Select_strict3) { WASM_EXEC_TEST(Select_strict3) {
WasmRunner<int32_t, int32_t> r(execution_tier); WasmRunner<int32_t, int32_t> r(execution_tier);
r.AllocateLocal(kWasmI32); r.AllocateLocal(kWasmI32);
...@@ -805,6 +849,21 @@ WASM_EXEC_TEST(Select_strict3) { ...@@ -805,6 +849,21 @@ WASM_EXEC_TEST(Select_strict3) {
} }
} }
WASM_EXEC_TEST(SelectWithType_strict3) {
EXPERIMENTAL_FLAG_SCOPE(anyref);
WasmRunner<int32_t, int32_t> r(execution_tier);
r.AllocateLocal(kWasmI32);
r.AllocateLocal(kWasmI32);
// select(b=5, c=6, a=b)
BUILD(r, WASM_SELECT_I(WASM_TEE_LOCAL(1, WASM_I32V_1(5)),
WASM_TEE_LOCAL(2, WASM_I32V_1(6)),
WASM_TEE_LOCAL(0, WASM_GET_LOCAL(1))));
FOR_INT32_INPUTS(i) {
int32_t expected = 5;
CHECK_EQ(expected, r.Call(i));
}
}
WASM_EXEC_TEST(BrIf_strict) { WASM_EXEC_TEST(BrIf_strict) {
WasmRunner<int32_t, int32_t> r(execution_tier); WasmRunner<int32_t, int32_t> r(execution_tier);
BUILD(r, WASM_BLOCK_I(WASM_BRV_IF(0, WASM_GET_LOCAL(0), BUILD(r, WASM_BLOCK_I(WASM_BRV_IF(0, WASM_GET_LOCAL(0),
......
...@@ -38,6 +38,8 @@ class TestSignatures { ...@@ -38,6 +38,8 @@ class TestSignatures {
sig_d_dd(1, 2, kDoubleTypes4), sig_d_dd(1, 2, kDoubleTypes4),
sig_r_v(1, 0, kRefTypes4), sig_r_v(1, 0, kRefTypes4),
sig_a_v(1, 0, kFuncTypes4), sig_a_v(1, 0, kFuncTypes4),
sig_r_r(1, 1, kRefTypes4),
sig_a_a(1, 1, kFuncTypes4),
sig_v_v(0, 0, kIntTypes4), sig_v_v(0, 0, kIntTypes4),
sig_v_i(0, 1, kIntTypes4), sig_v_i(0, 1, kIntTypes4),
sig_v_ii(0, 2, kIntTypes4), sig_v_ii(0, 2, kIntTypes4),
...@@ -93,6 +95,8 @@ class TestSignatures { ...@@ -93,6 +95,8 @@ class TestSignatures {
FunctionSig* r_v() { return &sig_r_v; } FunctionSig* r_v() { return &sig_r_v; }
FunctionSig* a_v() { return &sig_a_v; } FunctionSig* a_v() { return &sig_a_v; }
FunctionSig* r_r() { return &sig_r_r; }
FunctionSig* a_a() { return &sig_a_a; }
FunctionSig* v_v() { return &sig_v_v; } FunctionSig* v_v() { return &sig_v_v; }
FunctionSig* v_i() { return &sig_v_i; } FunctionSig* v_i() { return &sig_v_i; }
...@@ -153,6 +157,8 @@ class TestSignatures { ...@@ -153,6 +157,8 @@ class TestSignatures {
FunctionSig sig_r_v; FunctionSig sig_r_v;
FunctionSig sig_a_v; FunctionSig sig_a_v;
FunctionSig sig_r_r;
FunctionSig sig_a_a;
FunctionSig sig_v_v; FunctionSig sig_v_v;
FunctionSig sig_v_i; FunctionSig sig_v_i;
......
...@@ -140,6 +140,18 @@ ...@@ -140,6 +140,18 @@
kExprCatch, catchstmt, kExprEnd kExprCatch, catchstmt, kExprEnd
#define WASM_SELECT(tval, fval, cond) tval, fval, cond, kExprSelect #define WASM_SELECT(tval, fval, cond) tval, fval, cond, kExprSelect
#define WASM_SELECT_I(tval, fval, cond) \
tval, fval, cond, kExprSelectWithType, U32V_1(1), kLocalI32
#define WASM_SELECT_L(tval, fval, cond) \
tval, fval, cond, kExprSelectWithType, U32V_1(1), kLocalI64
#define WASM_SELECT_F(tval, fval, cond) \
tval, fval, cond, kExprSelectWithType, U32V_1(1), kLocalF32
#define WASM_SELECT_D(tval, fval, cond) \
tval, fval, cond, kExprSelectWithType, U32V_1(1), kLocalF64
#define WASM_SELECT_R(tval, fval, cond) \
tval, fval, cond, kExprSelectWithType, U32V_1(1), kLocalAnyRef
#define WASM_SELECT_A(tval, fval, cond) \
tval, fval, cond, kExprSelectWithType, U32V_1(1), kLocalAnyFunc
#define WASM_RETURN0 kExprReturn #define WASM_RETURN0 kExprReturn
#define WASM_RETURN1(val) val, kExprReturn #define WASM_RETURN1(val) val, kExprReturn
......
...@@ -389,6 +389,16 @@ class WasmGenerator { ...@@ -389,6 +389,16 @@ class WasmGenerator {
global_op<wanted_type>(data); global_op<wanted_type>(data);
} }
template <ValueType select_type>
void select_with_type(DataRange& data) {
static_assert(select_type != kWasmStmt, "illegal type for select");
Generate<select_type, select_type, kWasmI32>(data);
// num_types is always 1.
uint8_t num_types = 1;
builder_->EmitWithU8U8(kExprSelectWithType, num_types,
ValueTypes::ValueTypeCodeFor(select_type));
}
void set_global(DataRange& data) { global_op<kWasmStmt>(data); } void set_global(DataRange& data) { global_op<kWasmStmt>(data); }
template <ValueType... Types> template <ValueType... Types>
...@@ -603,6 +613,8 @@ void WasmGenerator::Generate<kWasmI32>(DataRange& data) { ...@@ -603,6 +613,8 @@ void WasmGenerator::Generate<kWasmI32>(DataRange& data) {
&WasmGenerator::get_local<kWasmI32>, &WasmGenerator::get_local<kWasmI32>,
&WasmGenerator::tee_local<kWasmI32>, &WasmGenerator::tee_local<kWasmI32>,
&WasmGenerator::get_global<kWasmI32>, &WasmGenerator::get_global<kWasmI32>,
&WasmGenerator::op<kExprSelect, kWasmI32, kWasmI32, kWasmI32>,
&WasmGenerator::select_with_type<kWasmI32>,
&WasmGenerator::call<kWasmI32>}; &WasmGenerator::call<kWasmI32>};
...@@ -669,6 +681,8 @@ void WasmGenerator::Generate<kWasmI64>(DataRange& data) { ...@@ -669,6 +681,8 @@ void WasmGenerator::Generate<kWasmI64>(DataRange& data) {
&WasmGenerator::get_local<kWasmI64>, &WasmGenerator::get_local<kWasmI64>,
&WasmGenerator::tee_local<kWasmI64>, &WasmGenerator::tee_local<kWasmI64>,
&WasmGenerator::get_global<kWasmI64>, &WasmGenerator::get_global<kWasmI64>,
&WasmGenerator::op<kExprSelect, kWasmI64, kWasmI64, kWasmI32>,
&WasmGenerator::select_with_type<kWasmI64>,
&WasmGenerator::call<kWasmI64>}; &WasmGenerator::call<kWasmI64>};
...@@ -702,6 +716,8 @@ void WasmGenerator::Generate<kWasmF32>(DataRange& data) { ...@@ -702,6 +716,8 @@ void WasmGenerator::Generate<kWasmF32>(DataRange& data) {
&WasmGenerator::get_local<kWasmF32>, &WasmGenerator::get_local<kWasmF32>,
&WasmGenerator::tee_local<kWasmF32>, &WasmGenerator::tee_local<kWasmF32>,
&WasmGenerator::get_global<kWasmF32>, &WasmGenerator::get_global<kWasmF32>,
&WasmGenerator::op<kExprSelect, kWasmF32, kWasmF32, kWasmI32>,
&WasmGenerator::select_with_type<kWasmF32>,
&WasmGenerator::call<kWasmF32>}; &WasmGenerator::call<kWasmF32>};
...@@ -735,6 +751,8 @@ void WasmGenerator::Generate<kWasmF64>(DataRange& data) { ...@@ -735,6 +751,8 @@ void WasmGenerator::Generate<kWasmF64>(DataRange& data) {
&WasmGenerator::get_local<kWasmF64>, &WasmGenerator::get_local<kWasmF64>,
&WasmGenerator::tee_local<kWasmF64>, &WasmGenerator::tee_local<kWasmF64>,
&WasmGenerator::get_global<kWasmF64>, &WasmGenerator::get_global<kWasmF64>,
&WasmGenerator::op<kExprSelect, kWasmF64, kWasmF64, kWasmI32>,
&WasmGenerator::select_with_type<kWasmF64>,
&WasmGenerator::call<kWasmF64>}; &WasmGenerator::call<kWasmF64>};
......
...@@ -2667,6 +2667,14 @@ TEST_F(FunctionBodyDecoderTest, Select) { ...@@ -2667,6 +2667,14 @@ TEST_F(FunctionBodyDecoderTest, Select) {
{WASM_SELECT(WASM_I64V_1(0), WASM_I64V_1(0), WASM_ZERO)}); {WASM_SELECT(WASM_I64V_1(0), WASM_I64V_1(0), WASM_ZERO)});
} }
TEST_F(FunctionBodyDecoderTest, Select_needs_value_type) {
WASM_FEATURE_SCOPE(anyref);
ExpectFailure(sigs.r_r(),
{WASM_SELECT(WASM_GET_LOCAL(0), WASM_GET_LOCAL(0), WASM_ZERO)});
ExpectFailure(sigs.a_a(),
{WASM_SELECT(WASM_GET_LOCAL(0), WASM_GET_LOCAL(0), WASM_ZERO)});
}
TEST_F(FunctionBodyDecoderTest, Select_fail1) { TEST_F(FunctionBodyDecoderTest, Select_fail1) {
ExpectFailure(sigs.i_i(), {WASM_SELECT(WASM_F32(0.0), WASM_GET_LOCAL(0), ExpectFailure(sigs.i_i(), {WASM_SELECT(WASM_F32(0.0), WASM_GET_LOCAL(0),
WASM_GET_LOCAL(0))}); WASM_GET_LOCAL(0))});
...@@ -2680,6 +2688,8 @@ TEST_F(FunctionBodyDecoderTest, Select_fail2) { ...@@ -2680,6 +2688,8 @@ TEST_F(FunctionBodyDecoderTest, Select_fail2) {
for (size_t i = 0; i < arraysize(kValueTypes); i++) { for (size_t i = 0; i < arraysize(kValueTypes); i++) {
ValueType type = kValueTypes[i]; ValueType type = kValueTypes[i];
if (type == kWasmI32) continue; if (type == kWasmI32) continue;
// Select without specified type is only allowed for number types.
if (type == kWasmAnyRef) continue;
ValueType types[] = {type, kWasmI32, type}; ValueType types[] = {type, kWasmI32, type};
FunctionSig sig(1, 2, types); FunctionSig sig(1, 2, types);
...@@ -2709,6 +2719,34 @@ TEST_F(FunctionBodyDecoderTest, Select_TypeCheck) { ...@@ -2709,6 +2719,34 @@ TEST_F(FunctionBodyDecoderTest, Select_TypeCheck) {
WASM_I64V_1(0))}); WASM_I64V_1(0))});
} }
TEST_F(FunctionBodyDecoderTest, SelectWithType) {
WASM_FEATURE_SCOPE(anyref);
ExpectValidates(sigs.i_i(), {WASM_SELECT_I(WASM_GET_LOCAL(0),
WASM_GET_LOCAL(0), WASM_ZERO)});
ExpectValidates(sigs.f_ff(),
{WASM_SELECT_F(WASM_F32(0.0), WASM_F32(0.0), WASM_ZERO)});
ExpectValidates(sigs.d_dd(),
{WASM_SELECT_D(WASM_F64(0.0), WASM_F64(0.0), WASM_ZERO)});
ExpectValidates(sigs.l_l(),
{WASM_SELECT_L(WASM_I64V_1(0), WASM_I64V_1(0), WASM_ZERO)});
ExpectValidates(sigs.r_r(),
{WASM_SELECT_R(WASM_REF_NULL, WASM_REF_NULL, WASM_ZERO)});
ExpectValidates(sigs.a_a(),
{WASM_SELECT_A(WASM_REF_NULL, WASM_REF_NULL, WASM_ZERO)});
}
TEST_F(FunctionBodyDecoderTest, SelectWithType_fail) {
WASM_FEATURE_SCOPE(anyref);
ExpectFailure(sigs.i_i(), {WASM_SELECT_F(WASM_GET_LOCAL(0), WASM_GET_LOCAL(0),
WASM_ZERO)});
ExpectFailure(sigs.f_ff(),
{WASM_SELECT_D(WASM_F32(0.0), WASM_F32(0.0), WASM_ZERO)});
ExpectFailure(sigs.d_dd(),
{WASM_SELECT_L(WASM_F64(0.0), WASM_F64(0.0), WASM_ZERO)});
ExpectFailure(sigs.l_l(),
{WASM_SELECT_I(WASM_I64V_1(0), WASM_I64V_1(0), WASM_ZERO)});
}
TEST_F(FunctionBodyDecoderTest, Throw) { TEST_F(FunctionBodyDecoderTest, Throw) {
WASM_FEATURE_SCOPE(eh); WASM_FEATURE_SCOPE(eh);
TestModuleBuilder builder; TestModuleBuilder builder;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment