Commit ccc74bc6 authored by Manos Koukoutos's avatar Manos Koukoutos Committed by V8 LUCI CQ

[wasm-gc] Remove 'let' opcode

This opcode is being removed in favor of pre-declared non-defaultable
locals (details are still TBD).

Bug: v8:9495
Change-Id: I96ac053a1b5a852310c5dc0bbaeab0cbf5384663
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3738743
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/main@{#81496}
parent 2650b3f7
......@@ -2382,16 +2382,6 @@ class LiftoffCompiler {
LocalSet(imm.index, true);
}
void AllocateLocals(FullDecoder* decoder, base::Vector<Value> local_values) {
// TODO(7748): Introduce typed functions bailout reason
unsupported(decoder, kGC, "let");
}
void DeallocateLocals(FullDecoder* decoder, uint32_t count) {
// TODO(7748): Introduce typed functions bailout reason
unsupported(decoder, kGC, "let");
}
Register GetGlobalBaseAndOffset(const WasmGlobal* global,
LiftoffRegList* pinned, uint32_t* offset) {
Register addr = pinned->set(__ GetUnusedRegister(kGpReg, {})).gp();
......
......@@ -874,7 +874,6 @@ enum ControlKind : uint8_t {
kControlIfElse,
kControlBlock,
kControlLoop,
kControlLet,
kControlTry,
kControlTryCatch,
kControlTryCatchAll,
......@@ -893,7 +892,6 @@ enum Reachability : uint8_t {
template <typename Value, Decoder::ValidateFlag validate>
struct ControlBase : public PcForErrors<validate> {
ControlKind kind = kControlBlock;
uint32_t locals_count = 0; // Additional locals introduced in this 'let'.
uint32_t stack_depth = 0; // Stack height at the beginning of the construct.
uint32_t init_stack_depth = 0; // Height of "locals initialization" stack
// at the beginning of the construct.
......@@ -912,13 +910,10 @@ struct ControlBase : public PcForErrors<validate> {
Reachability reachability)
: PcForErrors<validate>(pc),
kind(kind),
locals_count(locals_count),
stack_depth(stack_depth),
init_stack_depth(init_stack_depth),
reachability(reachability),
start_merge(reachability == kReachable) {
DCHECK(kind == kControlLet || locals_count == 0);
}
start_merge(reachability == kReachable) {}
// Check whether the current block is reachable.
bool reachable() const { return reachability == kReachable; }
......@@ -938,7 +933,6 @@ struct ControlBase : public PcForErrors<validate> {
bool is_onearmed_if() const { return kind == kControlIf; }
bool is_if_else() const { return kind == kControlIfElse; }
bool is_block() const { return kind == kControlBlock; }
bool is_let() const { return kind == kControlLet; }
bool is_loop() const { return kind == kControlLoop; }
bool is_incomplete_try() const { return kind == kControlTry; }
bool is_try_catch() const { return kind == kControlTryCatch; }
......@@ -1009,8 +1003,6 @@ struct ControlBase : public PcForErrors<validate> {
F(LocalSet, const Value& value, const IndexImmediate<validate>& imm) \
F(LocalTee, const Value& value, Value* result, \
const IndexImmediate<validate>& imm) \
F(AllocateLocals, base::Vector<Value> local_values) \
F(DeallocateLocals, uint32_t count) \
F(GlobalSet, const Value& value, const GlobalIndexImmediate<validate>& imm) \
F(TableGet, const Value& index, Value* result, \
const IndexImmediate<validate>& imm) \
......@@ -1314,17 +1306,6 @@ class WasmDecoder : public Decoder {
// No additional locals.
local_offsets[depth] = depth > 0 ? local_offsets[depth - 1] : 0;
break;
case kExprLet: {
depth++;
local_offsets.resize_no_init(depth + 1);
BlockTypeImmediate<validate> imm(WasmFeatures::All(), decoder, pc + 1,
nullptr);
uint32_t locals_length;
int new_locals_count = decoder->DecodeLocals(
pc + 1 + imm.length, &locals_length, base::Optional<uint32_t>());
local_offsets[depth] = local_offsets[depth - 1] + new_locals_count;
break;
}
case kExprLocalSet:
case kExprLocalTee: {
IndexImmediate<validate> imm(decoder, pc + 1, "local index");
......@@ -1734,14 +1715,6 @@ class WasmDecoder : public Decoder {
TagIndexImmediate<validate> imm(decoder, pc + 1);
return 1 + imm.length;
}
case kExprLet: {
BlockTypeImmediate<validate> imm(WasmFeatures::All(), decoder, pc + 1,
nullptr);
uint32_t locals_length;
int new_locals_count = decoder->DecodeLocals(
pc + 1 + imm.length, &locals_length, base::Optional<uint32_t>());
return 1 + imm.length + ((new_locals_count >= 0) ? locals_length : 0);
}
/********** Misc opcodes **********/
case kExprCallFunction:
......@@ -2184,9 +2157,6 @@ class WasmDecoder : public Decoder {
case kExprReturnCallIndirect:
case kExprUnreachable:
return {0, 0};
case kExprLet:
// TODO(7748): Implement
return {0, 0};
case kNumericPrefix:
case kAtomicPrefix:
case kSimdPrefix: {
......@@ -2722,9 +2692,6 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
case kControlTryCatchAll:
Append("A");
break;
case kControlLet:
Append("D");
break;
}
if (c.start_merge.arity) Append("%u-", c.start_merge.arity);
Append("%u", c.end_merge.arity);
......@@ -3008,34 +2975,6 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
return 1 + imm.length;
}
DECODE(Let) {
CHECK_PROTOTYPE_OPCODE(typed_funcref);
BlockTypeImmediate<validate> imm(this->enabled_, this, this->pc_ + 1,
this->module_);
if (!this->Validate(this->pc_ + 1, imm)) return 0;
// Temporarily add the let-defined values to the beginning of the function
// locals.
uint32_t locals_length;
int new_locals_count =
this->DecodeLocals(this->pc() + 1 + imm.length, &locals_length, 0);
if (new_locals_count < 0) {
return 0;
}
ArgVector let_local_values =
PeekArgs(base::VectorOf(this->local_types_.data(), new_locals_count));
ArgVector args = PeekArgs(imm.sig, new_locals_count);
Control* let_block = PushControl(kControlLet, new_locals_count,
let_local_values.length() + args.length());
SetBlockType(let_block, imm, args.begin());
CALL_INTERFACE_IF_OK_AND_REACHABLE(Block, let_block);
CALL_INTERFACE_IF_OK_AND_REACHABLE(AllocateLocals,
base::VectorOf(let_local_values));
Drop(new_locals_count); // Drop {let_local_values}.
DropArgs(imm.sig); // Drop {args}.
PushMergeValues(let_block, &let_block->start_merge);
return 1 + imm.length + locals_length;
}
DECODE(Loop) {
BlockTypeImmediate<validate> imm(this->enabled_, this, this->pc_ + 1,
this->module_);
......@@ -3110,13 +3049,6 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
if (c->is_onearmed_if()) {
if (!VALIDATE(TypeCheckOneArmedIf(c))) return 0;
}
if (c->is_let()) {
CALL_INTERFACE_IF_OK_AND_REACHABLE(DeallocateLocals, c->locals_count);
this->local_types_.erase(this->local_types_.begin(),
this->local_types_.begin() + c->locals_count);
this->num_locals_ -= c->locals_count;
}
}
if (control_.size() == 1) {
......@@ -3748,7 +3680,6 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
DECODE_IMPL(CatchAll);
DECODE_IMPL(BrOnNull);
DECODE_IMPL(BrOnNonNull);
DECODE_IMPL(Let);
DECODE_IMPL(Loop);
DECODE_IMPL(If);
DECODE_IMPL(Else);
......
......@@ -221,7 +221,7 @@ bool PrintRawWasmCode(AccountingAllocator* allocator, const FunctionBody& body,
os << RawOpcodeName(opcode) << ",";
if (opcode == kExprLoop || opcode == kExprIf || opcode == kExprBlock ||
opcode == kExprTry || opcode == kExprLet) {
opcode == kExprTry) {
if (i.pc()[1] & 0x80) {
uint32_t temp_length;
ValueType type =
......@@ -259,8 +259,7 @@ bool PrintRawWasmCode(AccountingAllocator* allocator, const FunctionBody& body,
case kExprLoop:
case kExprIf:
case kExprBlock:
case kExprTry:
case kExprLet: {
case kExprTry: {
BlockTypeImmediate<Decoder::kNoValidation> imm(WasmFeatures::All(), &i,
i.pc() + 1, module);
os << " @" << i.pc_offset();
......
......@@ -444,20 +444,6 @@ class WasmGraphBuildingInterface {
ssa_env_->locals[imm.index] = value.node;
}
void AllocateLocals(FullDecoder* decoder, base::Vector<Value> local_values) {
ZoneVector<TFNode*>* locals = &ssa_env_->locals;
locals->insert(locals->begin(), local_values.size(), nullptr);
for (uint32_t i = 0; i < local_values.size(); i++) {
(*locals)[i] =
builder_->SetType(local_values[i].node, local_values[i].type);
}
}
void DeallocateLocals(FullDecoder* decoder, uint32_t count) {
ZoneVector<TFNode*>* locals = &ssa_env_->locals;
locals->erase(locals->begin(), locals->begin() + count);
}
void GlobalGet(FullDecoder* decoder, Value* result,
const GlobalIndexImmediate<validate>& imm) {
SetAndTypeNode(result, builder_->GlobalGet(imm.index));
......@@ -1761,14 +1747,8 @@ class WasmGraphBuildingInterface {
switch (to->state) {
case SsaEnv::kUnreachable: { // Overwrite destination.
to->state = SsaEnv::kReached;
// There might be an offset in the locals due to a 'let'.
DCHECK_EQ(ssa_env_->locals.size(), decoder->num_locals());
DCHECK_GE(ssa_env_->locals.size(), to->locals.size());
uint32_t local_count_diff =
static_cast<uint32_t>(ssa_env_->locals.size() - to->locals.size());
to->locals = ssa_env_->locals;
to->locals.erase(to->locals.begin(),
to->locals.begin() + local_count_diff);
to->control = control();
to->effect = effect();
to->instance_cache = ssa_env_->instance_cache;
......@@ -1787,18 +1767,13 @@ class WasmGraphBuildingInterface {
to->effect = builder_->EffectPhi(2, inputs);
}
// Merge locals.
// There might be an offset in the locals due to a 'let'.
DCHECK_EQ(ssa_env_->locals.size(), decoder->num_locals());
DCHECK_GE(ssa_env_->locals.size(), to->locals.size());
uint32_t local_count_diff =
static_cast<uint32_t>(ssa_env_->locals.size() - to->locals.size());
for (uint32_t i = 0; i < to->locals.size(); i++) {
TFNode* a = to->locals[i];
TFNode* b = ssa_env_->locals[i + local_count_diff];
TFNode* b = ssa_env_->locals[i];
if (a != b) {
TFNode* inputs[] = {a, b, merge};
to->locals[i] = builder_->Phi(
decoder->local_type(i + local_count_diff), 2, inputs);
to->locals[i] = builder_->Phi(decoder->local_type(i), 2, inputs);
}
}
// Start a new merge from the instance cache.
......@@ -1814,16 +1789,10 @@ class WasmGraphBuildingInterface {
to->effect =
builder_->CreateOrMergeIntoEffectPhi(merge, to->effect, effect());
// Merge locals.
// There might be an offset in the locals due to a 'let'.
DCHECK_EQ(ssa_env_->locals.size(), decoder->num_locals());
DCHECK_GE(ssa_env_->locals.size(), to->locals.size());
uint32_t local_count_diff =
static_cast<uint32_t>(ssa_env_->locals.size() - to->locals.size());
for (uint32_t i = 0; i < to->locals.size(); i++) {
to->locals[i] = builder_->CreateOrMergeIntoPhi(
decoder->local_type(i + local_count_diff)
.machine_representation(),
merge, to->locals[i], ssa_env_->locals[i + local_count_diff]);
decoder->local_type(i).machine_representation(), merge,
to->locals[i], ssa_env_->locals[i]);
}
// Merge the instance caches.
builder_->MergeInstanceCacheInto(&to->instance_cache,
......
......@@ -33,27 +33,26 @@ bool V8_EXPORT_PRIVATE IsJSCompatibleSignature(const FunctionSig* sig,
// Format of all opcode macros: kExprName, binary, signature, wat name
// Control expressions and blocks.
#define FOREACH_CONTROL_OPCODE(V) \
V(Unreachable, 0x00, _, "unreachable") \
V(Nop, 0x01, _, "nop") \
V(Block, 0x02, _, "block") \
V(Loop, 0x03, _, "loop") \
V(If, 0x04, _, "if") \
V(Else, 0x05, _, "else") \
V(Try, 0x06, _, "try") /* eh_prototype */ \
V(Catch, 0x07, _, "catch") /* eh_prototype */ \
V(Throw, 0x08, _, "throw") /* eh_prototype */ \
V(Rethrow, 0x09, _, "rethrow") /* eh_prototype */ \
V(End, 0x0b, _, "end") \
V(Br, 0x0c, _, "br") \
V(BrIf, 0x0d, _, "br_if") \
V(BrTable, 0x0e, _, "br_table") \
V(Return, 0x0f, _, "return") \
V(Let, 0x17, _, "let") /* typed_funcref prototype */ \
V(Delegate, 0x18, _, "delegate") /* eh_prototype */ \
V(CatchAll, 0x19, _, "catch_all") /* eh_prototype */ \
V(BrOnNull, 0xd4, _, "br_on_null") /* gc prototype */ \
V(BrOnNonNull, 0xd6, _, "br_on_non_null") /* gc prototype */ \
#define FOREACH_CONTROL_OPCODE(V) \
V(Unreachable, 0x00, _, "unreachable") \
V(Nop, 0x01, _, "nop") \
V(Block, 0x02, _, "block") \
V(Loop, 0x03, _, "loop") \
V(If, 0x04, _, "if") \
V(Else, 0x05, _, "else") \
V(Try, 0x06, _, "try") \
V(Catch, 0x07, _, "catch") \
V(Throw, 0x08, _, "throw") \
V(Rethrow, 0x09, _, "rethrow") \
V(End, 0x0b, _, "end") \
V(Br, 0x0c, _, "br") \
V(BrIf, 0x0d, _, "br_if") \
V(BrTable, 0x0e, _, "br_table") \
V(Return, 0x0f, _, "return") \
V(Delegate, 0x18, _, "delegate") \
V(CatchAll, 0x19, _, "catch_all") \
V(BrOnNull, 0xd4, _, "br_on_null") /* gc prototype */ \
V(BrOnNonNull, 0xd6, _, "br_on_non_null") /* gc prototype */ \
V(NopForTestingUnsupportedInLiftoff, 0x16, _, "nop_for_testing")
// Constants, locals, globals, and calls.
......
......@@ -897,85 +897,6 @@ WASM_COMPILED_EXEC_TEST(WasmPackedStructS) {
tester.CheckResult(kF1, static_cast<int16_t>(expected_output_1));
}
TEST(WasmLetInstruction) {
WasmGCTester tester;
const byte type_index =
tester.DefineStruct({F(kWasmI32, true), F(kWasmI32, true)});
const byte let_local_index = 0;
const byte let_field_index = 0;
const byte kLetTest1 = tester.DefineFunction(
tester.sigs.i_v(), {},
{WASM_LET_1_I(
WASM_SEQ(kRefCode, type_index),
WASM_STRUCT_NEW_WITH_RTT(type_index, WASM_I32V(42), WASM_I32V(52),
WASM_RTT_CANON(type_index)),
WASM_STRUCT_GET(type_index, let_field_index,
WASM_LOCAL_GET(let_local_index))),
kExprEnd});
const byte let_2_field_index = 0;
const byte kLetTest2 = tester.DefineFunction(
tester.sigs.i_v(), {},
{WASM_LET_2_I(
kI32Code, WASM_I32_ADD(WASM_I32V(42), WASM_I32V(-32)),
WASM_SEQ(kRefCode, type_index),
WASM_STRUCT_NEW_WITH_RTT(type_index, WASM_I32V(42), WASM_I32V(52),
WASM_RTT_CANON(type_index)),
WASM_I32_MUL(WASM_STRUCT_GET(type_index, let_2_field_index,
WASM_LOCAL_GET(1)),
WASM_LOCAL_GET(0))),
kExprEnd});
const byte kLetTestLocals = tester.DefineFunction(
tester.sigs.i_i(), {kWasmI32},
{WASM_LOCAL_SET(1, WASM_I32V(100)),
WASM_LET_2_I(
kI32Code, WASM_I32V(1), kI32Code, WASM_I32V(10),
WASM_I32_SUB(WASM_I32_ADD(WASM_LOCAL_GET(0), // 1st let-local
WASM_LOCAL_GET(2)), // Parameter
WASM_I32_ADD(WASM_LOCAL_GET(1), // 2nd let-local
WASM_LOCAL_GET(3)))), // Function local
kExprEnd});
// Result: (1 + 1000) - (10 + 100) = 891
const byte let_erase_local_index = 0;
const byte kLetTestErase = tester.DefineFunction(
tester.sigs.i_v(), {kWasmI32},
{WASM_LOCAL_SET(let_erase_local_index, WASM_I32V(0)),
WASM_LET_1_V(kI32Code, WASM_I32V(1), WASM_NOP),
WASM_LOCAL_GET(let_erase_local_index), kExprEnd});
// The result should be 0 and not 1, as local_get(0) refers to the original
// local.
const byte kLetInLoop = tester.DefineFunction(
tester.sigs.i_i(), {},
{WASM_LOOP(WASM_LET_1_V(
kI32Code, WASM_I32V(10), // --
WASM_LOCAL_SET(1, WASM_I32_SUB(WASM_LOCAL_GET(1), WASM_I32V(10))),
WASM_BR_IF(1, WASM_I32_GES(WASM_LOCAL_GET(1), WASM_LOCAL_GET(0))))),
WASM_LOCAL_GET(0), WASM_END});
const byte kLetInBlock = tester.DefineFunction(
tester.sigs.i_i(), {},
{WASM_BLOCK(WASM_LET_1_V(
kI32Code, WASM_I32V(10), // --
WASM_BR_IF(1, WASM_I32_GES(WASM_LOCAL_GET(1), WASM_LOCAL_GET(0))),
WASM_LOCAL_SET(1, WASM_I32V(30)))),
WASM_LOCAL_GET(0), WASM_END});
tester.CompileModule();
tester.CheckResult(kLetTest1, 42);
tester.CheckResult(kLetTest2, 420);
tester.CheckResult(kLetTestLocals, 891, 1000);
tester.CheckResult(kLetTestErase, 0);
tester.CheckResult(kLetInLoop, 2, 52);
tester.CheckResult(kLetInLoop, -11, -1);
tester.CheckResult(kLetInBlock, 15, 15);
tester.CheckResult(kLetInBlock, 30, 5);
}
WASM_COMPILED_EXEC_TEST(WasmBasicArray) {
WasmGCTester tester(execution_tier);
if (!tester.HasSimdSupport(execution_tier)) return;
......
......@@ -629,21 +629,6 @@ inline uint16_t ExtractPrefixedOpcodeBytes(WasmOpcode opcode) {
#define WASM_RETURN_CALL_REF(func_ref, ...) \
__VA_ARGS__, func_ref, kExprReturnCallRef
// shift locals by 1; let (locals[0]: local_type) = value in ...
#define WASM_LET_1_V(local_type, value, ...) \
value, kExprLet, kVoidCode, U32V_1(1), U32V_1(1), local_type, __VA_ARGS__, \
kExprEnd
#define WASM_LET_1_I(local_type, value, ...) \
value, kExprLet, kI32Code, U32V_1(1), U32V_1(1), local_type, __VA_ARGS__, \
kExprEnd
// shift locals by 2;
// let (locals[0]: local_type_1) = value_1,
// (locals[1]: local_type_2) = value_2
// in ...
#define WASM_LET_2_I(local_type_1, value_1, local_type_2, value_2, ...) \
value_1, value_2, kExprLet, kI32Code, U32V_1(2), U32V_1(1), local_type_1, \
U32V_1(1), local_type_2, __VA_ARGS__, kExprEnd
#define WASM_NOT(x) x, kExprI32Eqz
#define WASM_SEQ(...) __VA_ARGS__
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --experimental-wasm-gc --no-liftoff
// Flags: --experimental-wasm-gc --no-liftoff --experimental-wasm-nn-locals
d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
......@@ -59,14 +59,14 @@ d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
.exportFunc();
builder.addFunction("loop_copy", kSig_v_v)
.addLocals(wasmRefType(array_index), 2)
.addLocals(kWasmI32, 2)
.addBody([
kExprLoop, kWasmVoid,
...wasmI32Const(0),
kExprLocalSet, 0,
kExprGlobalGet, from.index, kExprRefAsNonNull,
kExprGlobalGet, to.index, kExprRefAsNonNull,
kExprLet, kWasmVoid, 1, 2, kWasmRef, array_index,
kExprLocalSet, 2,
kExprGlobalGet, from.index, kExprRefAsNonNull, kExprLocalSet, 0,
kExprGlobalGet, to.index, kExprRefAsNonNull, kExprLocalSet, 1,
kExprLoop, kWasmVoid,
kExprLocalGet, 1, // array
kExprLocalGet, 2, // index
......@@ -81,10 +81,9 @@ d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
kExprLocalGet, 2, ...wasmI32Const(array_length), kExprI32LtU,
kExprBrIf, 0,
kExprEnd,
kExprEnd,
// Outer loop: run everything {iterations} times.
kExprLocalGet, 1, kExprI32Const, 1, kExprI32Add, kExprLocalSet, 1,
kExprLocalGet, 1, ...wasmI32Const(iterations), kExprI32LtS,
kExprLocalGet, 3, kExprI32Const, 3, kExprI32Add, kExprLocalSet, 3,
kExprLocalGet, 3, ...wasmI32Const(iterations), kExprI32LtS,
kExprBrIf, 0,
kExprEnd])
.exportFunc();
......
......@@ -13,6 +13,7 @@ d8.file.execute("test/mjsunit/wasm/exceptions-utils.js");
// Test that lowering a ror operator with int64-lowering does not produce
// floating control, which is incompatible with loop unrolling.
(function I64RorLoweringTest() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
builder.addMemory(1000, 1000);
......@@ -30,39 +31,19 @@ d8.file.execute("test/mjsunit/wasm/exceptions-utils.js");
.exportFunc();
let module = new WebAssembly.Module(builder.toBuffer());
let instance = new WebAssembly.Instance(module);
new WebAssembly.Instance(module);
})();
// Test the interaction between multireturn and loop unrolling.
(function MultiBlockResultTest() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
builder.addFunction("main", kSig_i_i)
.addBody([
...wasmI32Const(1),
kExprLet, kWasmVoid, 1, 1, kWasmI32,
kExprLoop, kWasmVoid,
...wasmI32Const(10),
kExprLet, kWasmVoid, 1, 1, kWasmI32,
kExprLocalGet, 0,
kExprLocalGet, 1,
kExprI32Sub,
kExprLocalGet, 2,
kExprI32Add,
kExprReturn, // (second let) - (first let) + parameter
kExprEnd,
kExprEnd,
kExprEnd,
...wasmI32Const(0)])
.exportAs("main");
let module = new WebAssembly.Module(builder.toBuffer());
let instance = new WebAssembly.Instance(module);
assertEquals(instance.exports.main(100), 109);
// TODO(manoskouk): Rewrite this test.
})();
// Test the interaction between tail calls and loop unrolling.
(function TailCallTest() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let callee = builder.addFunction("callee", kSig_i_i)
......
......@@ -274,7 +274,6 @@ const kWasmOpcodes = {
'ReturnCallIndirect': 0x13,
'CallRef': 0x14,
'ReturnCallRef': 0x15,
'Let': 0x17,
'Delegate': 0x18,
'Drop': 0x1a,
'Select': 0x1b,
......
......@@ -197,39 +197,6 @@ TEST_F(WasmLoopAssignmentAnalyzerTest, regress_642867) {
Analyze(code, code + arraysize(code));
}
TEST_F(WasmLoopAssignmentAnalyzerTest, LetInLoopAssigned) {
num_locals = 5;
static const byte code[] = {
WASM_LOOP(WASM_LET_1_V(kI32Code, WASM_I32V_1(42), WASM_SET_ZERO(3)))};
BitVector* assigned = Analyze(code, code + arraysize(code));
for (uint32_t i = 0; i <= num_locals; i++) {
EXPECT_EQ(assigned->Contains(i), i == 2);
}
}
TEST_F(WasmLoopAssignmentAnalyzerTest, LetInLoopNotAssigned) {
num_locals = 2;
static const byte code[] = {WASM_LOOP(
WASM_LET_1_V(kI32Code, WASM_I32V_1(42),
WASM_LET_1_V(kI32Code, WASM_I32V_1(42), WASM_SET_ZERO(0),
WASM_SET_ZERO(1))))};
BitVector* assigned = Analyze(code, code + arraysize(code));
for (uint32_t i = 0; i <= num_locals; i++) {
EXPECT_FALSE(assigned->Contains(i));
}
}
TEST_F(WasmLoopAssignmentAnalyzerTest, AssignmentOutsideOfLet) {
num_locals = 5;
static const byte code[] = {
WASM_LOOP(WASM_LET_1_V(kI32Code, WASM_I32V_1(42), WASM_SET_ZERO(3)),
WASM_SET_ZERO(4))};
BitVector* assigned = Analyze(code, code + arraysize(code));
for (uint32_t i = 0; i <= num_locals; i++) {
EXPECT_EQ(assigned->Contains(i), i == 2 || i == 4);
}
}
#undef WASM_SET_ZERO
} // namespace wasm
......
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