[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: Clemens Hammacher <clemensh@chromium.org> Cr-Commit-Position: refs/heads/master@{#61886}
This commit is contained in:
parent
f5ab7d38be
commit
d34178fd73
@ -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>
|
||||
struct BlockTypeImmediate {
|
||||
uint32_t length = 1;
|
||||
@ -216,7 +278,7 @@ struct BlockTypeImmediate {
|
||||
inline BlockTypeImmediate(const WasmFeatures& enabled, Decoder* decoder,
|
||||
const byte* pc) {
|
||||
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.
|
||||
if (!VALIDATE(enabled.mv)) {
|
||||
decoder->error(pc + 1, "invalid block type");
|
||||
@ -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 {
|
||||
if (type != kWasmVar) return 0;
|
||||
return static_cast<uint32_t>(sig->parameter_count());
|
||||
@ -1253,6 +1278,10 @@ class WasmDecoder : public Decoder {
|
||||
LocalIndexImmediate<validate> imm(decoder, pc);
|
||||
return 1 + imm.length;
|
||||
}
|
||||
case kExprSelectWithType: {
|
||||
SelectTypeImmediate<validate> imm(decoder, pc);
|
||||
return 1 + imm.length;
|
||||
}
|
||||
case kExprBrTable: {
|
||||
BranchTableImmediate<validate> imm(decoder, pc);
|
||||
BranchTableIterator<validate> iterator(decoder, imm);
|
||||
@ -1397,6 +1426,7 @@ class WasmDecoder : public Decoder {
|
||||
// clang-format off
|
||||
switch (opcode) {
|
||||
case kExprSelect:
|
||||
case kExprSelectWithType:
|
||||
return {3, 1};
|
||||
case kExprSetTable:
|
||||
FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE)
|
||||
@ -1895,10 +1925,28 @@ class WasmFullDecoder : public WasmDecoder<validate> {
|
||||
auto cond = Pop(2, kWasmI32);
|
||||
auto fval = Pop();
|
||||
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);
|
||||
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: {
|
||||
BranchDepthImmediate<validate> imm(this, this->pc_);
|
||||
if (!this->Validate(this->pc_, imm, control_.size())) break;
|
||||
|
@ -2837,6 +2837,11 @@ class ThreadImpl {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kExprSelectWithType: {
|
||||
SelectTypeImmediate<Decoder::kNoValidate> imm(&decoder, code->at(pc));
|
||||
len = 1 + imm.length;
|
||||
V8_FALLTHROUGH;
|
||||
}
|
||||
case kExprSelect: {
|
||||
WasmValue cond = Pop();
|
||||
WasmValue fval = Pop();
|
||||
|
@ -142,6 +142,7 @@ const char* WasmOpcodes::OpcodeName(WasmOpcode opcode) {
|
||||
CASE_OP(ReturnCallIndirect, "return_call_indirect")
|
||||
CASE_OP(Drop, "drop")
|
||||
CASE_OP(Select, "select")
|
||||
CASE_OP(SelectWithType, "select")
|
||||
CASE_OP(GetLocal, "local.get")
|
||||
CASE_OP(SetLocal, "local.set")
|
||||
CASE_OP(TeeLocal, "local.tee")
|
||||
|
@ -45,6 +45,7 @@ bool IsJSCompatibleSignature(const FunctionSig* sig, bool hasBigIntFeature);
|
||||
V(ReturnCallIndirect, 0x13, _) \
|
||||
V(Drop, 0x1a, _) \
|
||||
V(Select, 0x1b, _) \
|
||||
V(SelectWithType, 0x1c, _) \
|
||||
V(GetLocal, 0x20, _) \
|
||||
V(SetLocal, 0x21, _) \
|
||||
V(TeeLocal, 0x22, _) \
|
||||
|
@ -752,12 +752,19 @@ WASM_EXEC_TEST(Return_F64) {
|
||||
|
||||
WASM_EXEC_TEST(Select_float_parameters) {
|
||||
WasmRunner<float, float, float, int32_t> r(execution_tier);
|
||||
// return select(11, 22, a);
|
||||
BUILD(r,
|
||||
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));
|
||||
}
|
||||
|
||||
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) {
|
||||
WasmRunner<int32_t, int32_t> r(execution_tier);
|
||||
// return select(11, 22, a);
|
||||
@ -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) {
|
||||
WasmRunner<int32_t, int32_t> r(execution_tier);
|
||||
// select(a=0, a=1, a=2); return a
|
||||
@ -778,6 +796,18 @@ WASM_EXEC_TEST(Select_strict1) {
|
||||
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) {
|
||||
WasmRunner<int32_t, int32_t> r(execution_tier);
|
||||
r.AllocateLocal(kWasmI32);
|
||||
@ -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) {
|
||||
WasmRunner<int32_t, int32_t> r(execution_tier);
|
||||
r.AllocateLocal(kWasmI32);
|
||||
@ -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) {
|
||||
WasmRunner<int32_t, int32_t> r(execution_tier);
|
||||
BUILD(r, WASM_BLOCK_I(WASM_BRV_IF(0, WASM_GET_LOCAL(0),
|
||||
|
@ -38,6 +38,8 @@ class TestSignatures {
|
||||
sig_d_dd(1, 2, kDoubleTypes4),
|
||||
sig_r_v(1, 0, kRefTypes4),
|
||||
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_i(0, 1, kIntTypes4),
|
||||
sig_v_ii(0, 2, kIntTypes4),
|
||||
@ -93,6 +95,8 @@ class TestSignatures {
|
||||
|
||||
FunctionSig* r_v() { return &sig_r_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_i() { return &sig_v_i; }
|
||||
@ -153,6 +157,8 @@ class TestSignatures {
|
||||
|
||||
FunctionSig sig_r_v;
|
||||
FunctionSig sig_a_v;
|
||||
FunctionSig sig_r_r;
|
||||
FunctionSig sig_a_a;
|
||||
|
||||
FunctionSig sig_v_v;
|
||||
FunctionSig sig_v_i;
|
||||
|
@ -140,6 +140,18 @@
|
||||
kExprCatch, catchstmt, kExprEnd
|
||||
|
||||
#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_RETURN1(val) val, kExprReturn
|
||||
|
@ -389,6 +389,16 @@ class WasmGenerator {
|
||||
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); }
|
||||
|
||||
template <ValueType... Types>
|
||||
@ -603,6 +613,8 @@ void WasmGenerator::Generate<kWasmI32>(DataRange& data) {
|
||||
&WasmGenerator::get_local<kWasmI32>,
|
||||
&WasmGenerator::tee_local<kWasmI32>,
|
||||
&WasmGenerator::get_global<kWasmI32>,
|
||||
&WasmGenerator::op<kExprSelect, kWasmI32, kWasmI32, kWasmI32>,
|
||||
&WasmGenerator::select_with_type<kWasmI32>,
|
||||
|
||||
&WasmGenerator::call<kWasmI32>};
|
||||
|
||||
@ -669,6 +681,8 @@ void WasmGenerator::Generate<kWasmI64>(DataRange& data) {
|
||||
&WasmGenerator::get_local<kWasmI64>,
|
||||
&WasmGenerator::tee_local<kWasmI64>,
|
||||
&WasmGenerator::get_global<kWasmI64>,
|
||||
&WasmGenerator::op<kExprSelect, kWasmI64, kWasmI64, kWasmI32>,
|
||||
&WasmGenerator::select_with_type<kWasmI64>,
|
||||
|
||||
&WasmGenerator::call<kWasmI64>};
|
||||
|
||||
@ -702,6 +716,8 @@ void WasmGenerator::Generate<kWasmF32>(DataRange& data) {
|
||||
&WasmGenerator::get_local<kWasmF32>,
|
||||
&WasmGenerator::tee_local<kWasmF32>,
|
||||
&WasmGenerator::get_global<kWasmF32>,
|
||||
&WasmGenerator::op<kExprSelect, kWasmF32, kWasmF32, kWasmI32>,
|
||||
&WasmGenerator::select_with_type<kWasmF32>,
|
||||
|
||||
&WasmGenerator::call<kWasmF32>};
|
||||
|
||||
@ -735,6 +751,8 @@ void WasmGenerator::Generate<kWasmF64>(DataRange& data) {
|
||||
&WasmGenerator::get_local<kWasmF64>,
|
||||
&WasmGenerator::tee_local<kWasmF64>,
|
||||
&WasmGenerator::get_global<kWasmF64>,
|
||||
&WasmGenerator::op<kExprSelect, kWasmF64, kWasmF64, kWasmI32>,
|
||||
&WasmGenerator::select_with_type<kWasmF64>,
|
||||
|
||||
&WasmGenerator::call<kWasmF64>};
|
||||
|
||||
|
@ -2667,6 +2667,14 @@ TEST_F(FunctionBodyDecoderTest, Select) {
|
||||
{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) {
|
||||
ExpectFailure(sigs.i_i(), {WASM_SELECT(WASM_F32(0.0), WASM_GET_LOCAL(0),
|
||||
WASM_GET_LOCAL(0))});
|
||||
@ -2680,6 +2688,8 @@ TEST_F(FunctionBodyDecoderTest, Select_fail2) {
|
||||
for (size_t i = 0; i < arraysize(kValueTypes); i++) {
|
||||
ValueType type = kValueTypes[i];
|
||||
if (type == kWasmI32) continue;
|
||||
// Select without specified type is only allowed for number types.
|
||||
if (type == kWasmAnyRef) continue;
|
||||
|
||||
ValueType types[] = {type, kWasmI32, type};
|
||||
FunctionSig sig(1, 2, types);
|
||||
@ -2709,6 +2719,34 @@ TEST_F(FunctionBodyDecoderTest, Select_TypeCheck) {
|
||||
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) {
|
||||
WASM_FEATURE_SCOPE(eh);
|
||||
TestModuleBuilder builder;
|
||||
|
Loading…
Reference in New Issue
Block a user