Reland "[wasm-gc] Liftoff support part 5: i31"

This is a reland of a3ce2f6da2
(No changes; was reverted because a dependency was reverted.)

Original change's description:
> [wasm-gc] Liftoff support part 5: i31
>
> This implements support for i31.get_s and i31.get_u.
>
> Bug: v8:7748
> Change-Id: Icbfddbc2ff46b4eb6bf3edf7b3a794f9797361d4
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2595309
> Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
> Reviewed-by: Clemens Backes <clemensb@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#71808}

Bug: v8:7748
Change-Id: Id8e66cab285d2a36fcd712b92a522e83dea93193
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2617089
Reviewed-by: Clemens Backes <clemensb@chromium.org>
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#71984}
This commit is contained in:
Jakob Kummerow 2020-12-16 23:29:12 +01:00 committed by Commit Bot
parent 2651820e68
commit 432c0a78e9
5 changed files with 42 additions and 17 deletions

View File

@ -703,11 +703,13 @@ void LiftoffAssembler::StoreTaggedPointer(Register dst_addr,
LiftoffRegister src,
LiftoffRegList pinned) {
STATIC_ASSERT(kTaggedSize == kInt32Size);
// Store the value.
UseScratchRegisterScope temps(this);
MemOperand dst_op =
liftoff::GetMemOp(this, &temps, dst_addr, offset_reg, offset_imm);
str(src.gp(), dst_op);
{
// Store the value.
UseScratchRegisterScope temps(this);
MemOperand dst_op =
liftoff::GetMemOp(this, &temps, dst_addr, offset_reg, offset_imm);
str(src.gp(), dst_op);
}
// The write barrier.
Label write_barrier;
Label exit;

View File

@ -71,6 +71,7 @@ inline void Load(LiftoffAssembler* assm, LiftoffRegister dst, Register base,
case ValueType::kI32:
case ValueType::kOptRef:
case ValueType::kRef:
case ValueType::kRtt:
assm->mov(dst.gp(), src);
break;
case ValueType::kI64:

View File

@ -4136,6 +4136,9 @@ class LiftoffCompiler {
__ PushRegister(kWasmI32, len);
}
// 1 bit Smi tag, 31 bits Smi shift, 1 bit i31ref high-bit truncation.
constexpr static int kI31To32BitSmiShift = 33;
void I31New(FullDecoder* decoder, const Value& input, Value* result) {
LiftoffRegister src = __ PopToRegister();
LiftoffRegister dst = __ GetUnusedRegister(kGpReg, {src}, {});
@ -4144,20 +4147,33 @@ class LiftoffCompiler {
__ emit_i32_shli(dst.gp(), src.gp(), kSmiTagSize);
} else {
DCHECK(SmiValuesAre32Bits());
// 1 bit Smi tag, 31 bits Smi shift, 1 bit i31ref high-bit truncation.
constexpr int kI31To32BitSmiShift = 33;
__ emit_i64_shli(dst, src, kI31To32BitSmiShift);
}
__ PushRegister(kWasmI31Ref, dst);
}
void I31GetS(FullDecoder* decoder, const Value& input, Value* result) {
// TODO(7748): Implement.
unsupported(decoder, kGC, "i31.get_s");
LiftoffRegister src = __ PopToRegister();
LiftoffRegister dst = __ GetUnusedRegister(kGpReg, {src}, {});
if (SmiValuesAre31Bits()) {
__ emit_i32_sari(dst.gp(), src.gp(), kSmiTagSize);
} else {
DCHECK(SmiValuesAre32Bits());
__ emit_i64_sari(dst, src, kI31To32BitSmiShift);
}
__ PushRegister(kWasmI32, dst);
}
void I31GetU(FullDecoder* decoder, const Value& input, Value* result) {
// TODO(7748): Implement.
unsupported(decoder, kGC, "i31.get_u");
LiftoffRegister src = __ PopToRegister();
LiftoffRegister dst = __ GetUnusedRegister(kGpReg, {src}, {});
if (SmiValuesAre31Bits()) {
__ emit_i32_shri(dst.gp(), src.gp(), kSmiTagSize);
} else {
DCHECK(SmiValuesAre32Bits());
__ emit_i64_shri(dst, src, kI31To32BitSmiShift);
}
__ PushRegister(kWasmI32, dst);
}
void RttCanon(FullDecoder* decoder, const HeapTypeImmediate<validate>& imm,

View File

@ -91,6 +91,7 @@ inline void Load(LiftoffAssembler* assm, LiftoffRegister dst, Operand src,
case ValueType::kI64:
case ValueType::kOptRef:
case ValueType::kRef:
case ValueType::kRtt:
assm->movq(dst.gp(), src);
break;
case ValueType::kF32:

View File

@ -42,6 +42,7 @@ class WasmGCTester {
flag_liftoff_only(
&v8::internal::FLAG_liftoff_only,
execution_tier == TestExecutionTier::kLiftoff ? true : false),
flag_tierup(&v8::internal::FLAG_wasm_tier_up, false),
zone(&allocator, ZONE_NAME),
builder_(&zone),
isolate_(CcTest::InitIsolateOnce()),
@ -182,6 +183,7 @@ class WasmGCTester {
const FlagScope<bool> flag_typedfuns;
const FlagScope<bool> flag_liftoff;
const FlagScope<bool> flag_liftoff_only;
const FlagScope<bool> flag_tierup;
v8::internal::AccountingAllocator allocator;
Zone zone;
@ -1091,8 +1093,9 @@ WASM_COMPILED_EXEC_TEST(RefTestCastNull) {
tester.CheckHasThrown(kRefCastNull, 0);
}
TEST(BasicI31) {
WasmGCTester tester;
WASM_COMPILED_EXEC_TEST(BasicI31) {
WasmGCTester tester(execution_tier);
FLAG_experimental_liftoff_extern_ref = true;
const byte kSigned = tester.DefineFunction(
tester.sigs.i_i(), {},
{WASM_I31_GET_S(WASM_I31_NEW(WASM_LOCAL_GET(0))), kExprEnd});
@ -1112,8 +1115,9 @@ TEST(BasicI31) {
tester.CheckResult(kUnsigned, 0x7FFFFFFF, 0x7FFFFFFF);
}
TEST(I31Casts) {
WasmGCTester tester;
WASM_COMPILED_EXEC_TEST(I31Casts) {
WasmGCTester tester(execution_tier);
FLAG_experimental_liftoff_extern_ref = true;
const byte struct_type = tester.DefineStruct({F(wasm::kWasmI32, true)});
const byte i31_rtt =
tester.AddGlobal(ValueType::Rtt(HeapType::kI31, 1), false,
@ -1173,8 +1177,9 @@ TEST(I31Casts) {
// This flushed out a few bugs, so it serves as a regression test. It can also
// be modified (made to run longer) to measure performance of casts.
TEST(CastsBenchmark) {
WasmGCTester tester;
WASM_COMPILED_EXEC_TEST(CastsBenchmark) {
WasmGCTester tester(execution_tier);
FLAG_experimental_liftoff_extern_ref = true;
const byte SuperType = tester.DefineStruct({F(wasm::kWasmI32, true)});
const byte SubType =
tester.DefineStruct({F(wasm::kWasmI32, true), F(wasm::kWasmI32, true)});