Commit a3ce2f6d authored by Jakob Kummerow's avatar Jakob Kummerow Committed by Commit Bot

[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: 's avatarClemens Backes <clemensb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#71808}
parent 45414e11
...@@ -703,11 +703,13 @@ void LiftoffAssembler::StoreTaggedPointer(Register dst_addr, ...@@ -703,11 +703,13 @@ void LiftoffAssembler::StoreTaggedPointer(Register dst_addr,
LiftoffRegister src, LiftoffRegister src,
LiftoffRegList pinned) { LiftoffRegList pinned) {
STATIC_ASSERT(kTaggedSize == kInt32Size); STATIC_ASSERT(kTaggedSize == kInt32Size);
{
// Store the value. // Store the value.
UseScratchRegisterScope temps(this); UseScratchRegisterScope temps(this);
MemOperand dst_op = MemOperand dst_op =
liftoff::GetMemOp(this, &temps, dst_addr, offset_reg, offset_imm); liftoff::GetMemOp(this, &temps, dst_addr, offset_reg, offset_imm);
str(src.gp(), dst_op); str(src.gp(), dst_op);
}
// The write barrier. // The write barrier.
Label write_barrier; Label write_barrier;
Label exit; Label exit;
......
...@@ -71,6 +71,7 @@ inline void Load(LiftoffAssembler* assm, LiftoffRegister dst, Register base, ...@@ -71,6 +71,7 @@ inline void Load(LiftoffAssembler* assm, LiftoffRegister dst, Register base,
case ValueType::kI32: case ValueType::kI32:
case ValueType::kOptRef: case ValueType::kOptRef:
case ValueType::kRef: case ValueType::kRef:
case ValueType::kRtt:
assm->mov(dst.gp(), src); assm->mov(dst.gp(), src);
break; break;
case ValueType::kI64: case ValueType::kI64:
......
...@@ -4063,6 +4063,9 @@ class LiftoffCompiler { ...@@ -4063,6 +4063,9 @@ class LiftoffCompiler {
__ PushRegister(kWasmI32, len); __ 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) { void I31New(FullDecoder* decoder, const Value& input, Value* result) {
LiftoffRegister src = __ PopToRegister(); LiftoffRegister src = __ PopToRegister();
LiftoffRegister dst = __ GetUnusedRegister(kGpReg, {src}, {}); LiftoffRegister dst = __ GetUnusedRegister(kGpReg, {src}, {});
...@@ -4071,20 +4074,33 @@ class LiftoffCompiler { ...@@ -4071,20 +4074,33 @@ class LiftoffCompiler {
__ emit_i32_shli(dst.gp(), src.gp(), kSmiTagSize); __ emit_i32_shli(dst.gp(), src.gp(), kSmiTagSize);
} else { } else {
DCHECK(SmiValuesAre32Bits()); 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); __ emit_i64_shli(dst, src, kI31To32BitSmiShift);
} }
__ PushRegister(kWasmI31Ref, dst); __ PushRegister(kWasmI31Ref, dst);
} }
void I31GetS(FullDecoder* decoder, const Value& input, Value* result) { void I31GetS(FullDecoder* decoder, const Value& input, Value* result) {
// TODO(7748): Implement. LiftoffRegister src = __ PopToRegister();
unsupported(decoder, kGC, "i31.get_s"); 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) { void I31GetU(FullDecoder* decoder, const Value& input, Value* result) {
// TODO(7748): Implement. LiftoffRegister src = __ PopToRegister();
unsupported(decoder, kGC, "i31.get_u"); 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, void RttCanon(FullDecoder* decoder, const HeapTypeImmediate<validate>& imm,
......
...@@ -90,6 +90,7 @@ inline void Load(LiftoffAssembler* assm, LiftoffRegister dst, Operand src, ...@@ -90,6 +90,7 @@ inline void Load(LiftoffAssembler* assm, LiftoffRegister dst, Operand src,
case ValueType::kI64: case ValueType::kI64:
case ValueType::kOptRef: case ValueType::kOptRef:
case ValueType::kRef: case ValueType::kRef:
case ValueType::kRtt:
assm->movq(dst.gp(), src); assm->movq(dst.gp(), src);
break; break;
case ValueType::kF32: case ValueType::kF32:
......
...@@ -42,6 +42,7 @@ class WasmGCTester { ...@@ -42,6 +42,7 @@ class WasmGCTester {
flag_liftoff_only( flag_liftoff_only(
&v8::internal::FLAG_liftoff_only, &v8::internal::FLAG_liftoff_only,
execution_tier == TestExecutionTier::kLiftoff ? true : false), execution_tier == TestExecutionTier::kLiftoff ? true : false),
flag_tierup(&v8::internal::FLAG_wasm_tier_up, false),
zone(&allocator, ZONE_NAME), zone(&allocator, ZONE_NAME),
builder_(&zone), builder_(&zone),
isolate_(CcTest::InitIsolateOnce()), isolate_(CcTest::InitIsolateOnce()),
...@@ -182,6 +183,7 @@ class WasmGCTester { ...@@ -182,6 +183,7 @@ class WasmGCTester {
const FlagScope<bool> flag_typedfuns; const FlagScope<bool> flag_typedfuns;
const FlagScope<bool> flag_liftoff; const FlagScope<bool> flag_liftoff;
const FlagScope<bool> flag_liftoff_only; const FlagScope<bool> flag_liftoff_only;
const FlagScope<bool> flag_tierup;
v8::internal::AccountingAllocator allocator; v8::internal::AccountingAllocator allocator;
Zone zone; Zone zone;
...@@ -1086,8 +1088,9 @@ TEST(RefTestCastNull) { ...@@ -1086,8 +1088,9 @@ TEST(RefTestCastNull) {
tester.CheckHasThrown(kRefCastNull, 0); tester.CheckHasThrown(kRefCastNull, 0);
} }
TEST(BasicI31) { WASM_COMPILED_EXEC_TEST(BasicI31) {
WasmGCTester tester; WasmGCTester tester(execution_tier);
FLAG_experimental_liftoff_extern_ref = true;
const byte kSigned = tester.DefineFunction( const byte kSigned = tester.DefineFunction(
tester.sigs.i_i(), {}, tester.sigs.i_i(), {},
{WASM_I31_GET_S(WASM_I31_NEW(WASM_GET_LOCAL(0))), kExprEnd}); {WASM_I31_GET_S(WASM_I31_NEW(WASM_GET_LOCAL(0))), kExprEnd});
...@@ -1107,8 +1110,9 @@ TEST(BasicI31) { ...@@ -1107,8 +1110,9 @@ TEST(BasicI31) {
tester.CheckResult(kUnsigned, 0x7FFFFFFF, 0x7FFFFFFF); tester.CheckResult(kUnsigned, 0x7FFFFFFF, 0x7FFFFFFF);
} }
TEST(I31Casts) { WASM_COMPILED_EXEC_TEST(I31Casts) {
WasmGCTester tester; WasmGCTester tester(execution_tier);
FLAG_experimental_liftoff_extern_ref = true;
const byte struct_type = tester.DefineStruct({F(wasm::kWasmI32, true)}); const byte struct_type = tester.DefineStruct({F(wasm::kWasmI32, true)});
const byte i31_rtt = const byte i31_rtt =
tester.AddGlobal(ValueType::Rtt(HeapType::kI31, 1), false, tester.AddGlobal(ValueType::Rtt(HeapType::kI31, 1), false,
...@@ -1168,8 +1172,9 @@ TEST(I31Casts) { ...@@ -1168,8 +1172,9 @@ TEST(I31Casts) {
// This flushed out a few bugs, so it serves as a regression test. It can also // 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. // be modified (made to run longer) to measure performance of casts.
TEST(CastsBenchmark) { WASM_COMPILED_EXEC_TEST(CastsBenchmark) {
WasmGCTester tester; WasmGCTester tester(execution_tier);
FLAG_experimental_liftoff_extern_ref = true;
const byte SuperType = tester.DefineStruct({F(wasm::kWasmI32, true)}); const byte SuperType = tester.DefineStruct({F(wasm::kWasmI32, true)});
const byte SubType = const byte SubType =
tester.DefineStruct({F(wasm::kWasmI32, true), F(wasm::kWasmI32, true)}); tester.DefineStruct({F(wasm::kWasmI32, true), F(wasm::kWasmI32, true)});
......
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