[maglev] Support polymorphic loads of doubles

Drive-by:
- Make LoadDoubleField arch-indepedent
- Fix map check in LoadPolymorphicTaggedField

Bug: v8:7700
Change-Id: I138056c31ac9004971420f58db7df7e535d603e4
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4194717
Auto-Submit: Victor Gomes <victorgomes@chromium.org>
Commit-Queue: Victor Gomes <victorgomes@chromium.org>
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
Cr-Commit-Position: refs/heads/main@{#85485}
This commit is contained in:
Victor Gomes 2023-01-26 10:30:02 +01:00 committed by V8 LUCI CQ
parent a0417c29d8
commit cca14c7834
9 changed files with 194 additions and 89 deletions

View File

@ -535,6 +535,17 @@ inline void MaglevAssembler::JumpIfTaggedEqual(Register r1, Register r2,
b(target, eq);
}
inline void MaglevAssembler::LoadHeapNumberValue(DoubleRegister result,
Register heap_number) {
Ldr(result, FieldMemOperand(heap_number, HeapNumber::kValueOffset));
}
inline void MaglevAssembler::SmiToDouble(DoubleRegister result, Register smi) {
AssertSmi(smi);
SmiUntag(smi);
Scvtf(result, smi.W());
}
inline void MaglevAssembler::Pop(Register dst) { Pop(dst, padreg); }
inline void MaglevAssembler::AssertStackSizeCorrect() {

View File

@ -2000,22 +2000,6 @@ DEF_OPERATION(LoadDoubleTypedArrayElementNoDeopt, DoubleRegister,
ToDoubleRegister, /*check_detached*/ false)
#undef DEF_OPERATION
void LoadDoubleField::SetValueLocationConstraints() {
UseRegister(object_input());
DefineAsRegister(this);
}
void LoadDoubleField::GenerateCode(MaglevAssembler* masm,
const ProcessingState& state) {
MaglevAssembler::ScratchRegisterScope temps(masm);
Register tmp = temps.Acquire();
Register object = ToRegister(object_input());
__ AssertNotSmi(object);
__ DecompressAnyTagged(tmp, FieldMemOperand(object, offset()));
__ AssertNotSmi(tmp);
__ Ldr(ToDoubleRegister(result()),
FieldMemOperand(tmp, HeapNumber::kValueOffset));
}
void LoadFixedArrayElement::SetValueLocationConstraints() {
UseRegister(elements_input());
UseRegister(index_input());

View File

@ -37,6 +37,59 @@ void MaglevAssembler::LoadSingleCharacterString(Register result,
table, FixedArray::kHeaderSize + char_code * kTaggedSize));
}
void MaglevAssembler::CheckMaps(ZoneVector<compiler::MapRef> const& maps,
Register map, Label* is_number,
Label* no_match) {
Label done;
bool has_heap_number_map = false;
for (auto it = maps.begin(); it != maps.end(); ++it) {
if (it->IsHeapNumberMap()) {
has_heap_number_map = true;
}
CompareTagged(map, it->object());
if (it == maps.end() - 1) {
JumpIfNotEqual(no_match);
// Fallthrough...
} else {
JumpIfEqual(&done);
}
}
// Bind number case here if one of the maps is HeapNumber.
if (has_heap_number_map) {
DCHECK(!is_number->is_bound());
bind(is_number);
}
bind(&done);
}
void MaglevAssembler::LoadDataField(
const compiler::PropertyAccessInfo& access_info, Register result,
Register object, Register scratch) {
DCHECK(access_info.IsDataField() || access_info.IsFastDataConstant());
// TODO(victorgomes): Support ConstantDataFields.
Register load_source = object;
// Resolve property holder.
if (access_info.holder().has_value()) {
load_source = scratch;
Move(load_source, access_info.holder().value().object());
}
FieldIndex field_index = access_info.field_index();
if (!field_index.is_inobject()) {
Register load_source_object = load_source;
if (load_source == object) {
load_source = scratch;
}
// The field is in the property array, first load it from there.
AssertNotSmi(load_source_object);
DecompressAnyTagged(load_source,
FieldMemOperand(load_source_object,
JSReceiver::kPropertiesOrHashOffset));
}
AssertNotSmi(load_source);
DecompressAnyTagged(result,
FieldMemOperand(load_source, field_index.offset()));
}
} // namespace maglev
} // namespace internal
} // namespace v8

View File

@ -209,6 +209,8 @@ class MaglevAssembler : public MacroAssembler {
inline void JumpIfTaggedEqual(Register r1, Register r2, Label* target,
Label::Distance distance = Label::kFar);
inline void SmiToDouble(DoubleRegister result, Register smi);
// TODO(victorgomes): Import baseline Pop(T...) methods.
inline void Pop(Register dst);
using MacroAssembler::Pop;
@ -224,6 +226,14 @@ class MaglevAssembler : public MacroAssembler {
inline void AssertStackSizeCorrect();
inline void LoadHeapNumberValue(DoubleRegister result, Register heap_number);
void CheckMaps(ZoneVector<compiler::MapRef> const& maps, Register map,
Label* is_number, Label* no_match);
void LoadDataField(const compiler::PropertyAccessInfo& access_info,
Register result, Register object, Register scratch);
void MaybeEmitDeoptBuiltinsCall(size_t eager_deopt_count,
Label* eager_deopt_entry,
size_t lazy_deopt_count,

View File

@ -2099,17 +2099,20 @@ bool MaglevGraphBuilder::TryBuildNamedAccess(
return false;
}
bool only_double_or_smi_load = true;
// Check if we support the polymorphic load.
for (compiler::PropertyAccessInfo access_info : access_infos) {
switch (access_info.kind()) {
case compiler::PropertyAccessInfo::kNotFound:
case compiler::PropertyAccessInfo::kModuleExport:
only_double_or_smi_load = false;
break;
case compiler::PropertyAccessInfo::kDataField:
case compiler::PropertyAccessInfo::kFastDataConstant:
if (access_info.field_index().is_double()) {
return false;
}
only_double_or_smi_load &=
(access_info.field_index().is_double() ||
access_info.field_representation().IsSmi());
break;
default:
// TODO(victorgomes): Support other access.
@ -2134,8 +2137,13 @@ bool MaglevGraphBuilder::TryBuildNamedAccess(
}
}
SetAccumulator(AddNewNode<LoadPolymorphicTaggedField>(
{lookup_start_object}, std::move(access_infos)));
if (only_double_or_smi_load) {
SetAccumulator(AddNewNode<LoadPolymorphicDoubleField>(
{lookup_start_object}, std::move(access_infos)));
} else {
SetAccumulator(AddNewNode<LoadPolymorphicTaggedField>(
{lookup_start_object}, std::move(access_infos)));
}
return true;
}
}

View File

@ -891,6 +891,22 @@ void GetIterator::GenerateCode(MaglevAssembler* masm,
masm->DefineExceptionHandlerAndLazyDeoptPoint(this);
}
void LoadDoubleField::SetValueLocationConstraints() {
UseRegister(object_input());
DefineAsRegister(this);
set_temporaries_needed(1);
}
void LoadDoubleField::GenerateCode(MaglevAssembler* masm,
const ProcessingState& state) {
MaglevAssembler::ScratchRegisterScope temps(masm);
Register tmp = temps.Acquire();
Register object = ToRegister(object_input());
__ AssertNotSmi(object);
__ DecompressAnyTagged(tmp, FieldMemOperand(object, offset()));
__ AssertNotSmi(tmp);
__ LoadHeapNumberValue(ToDoubleRegister(result()), tmp);
}
void LoadTaggedField::SetValueLocationConstraints() {
UseRegister(object_input());
DefineAsRegister(this);
@ -914,40 +930,18 @@ void LoadPolymorphicTaggedField::GenerateCode(MaglevAssembler* masm,
Register result_reg = ToRegister(result());
Register object = ToRegister(object_input());
Register object_map = temps.Acquire();
Label done;
Label is_number;
Condition is_smi = __ CheckSmi(object);
__ JumpIf(is_smi, &is_number);
__ LoadMap(object_map, object);
for (compiler::PropertyAccessInfo access_info : access_infos_) {
for (const compiler::PropertyAccessInfo& access_info : access_infos_) {
Label next;
Label do_load;
// Check if {object_map} one of the lookup_start_object_maps.
bool has_heap_number_map = false;
auto& maps = access_info.lookup_start_object_maps();
for (auto it = maps.begin(); it != maps.end(); ++it) {
if (it->IsHeapNumberMap()) {
has_heap_number_map = true;
}
__ CompareTagged(object_map, it->object());
if (it == maps.end() - 1) {
__ JumpIfNotEqual(&next);
// Fallthrough to {do_load}.
} else {
__ JumpIfEqual(&do_load);
__ Jump(&next);
}
}
// Bind number case here if one of the maps is HeapNumber.
if (has_heap_number_map && !is_number.is_bound()) {
__ bind(&is_number);
}
// Do the load based on the PropertyAccess kind.
__ bind(&do_load);
__ CheckMaps(access_info.lookup_start_object_maps(), object_map, &is_number,
&next);
switch (access_info.kind()) {
case compiler::PropertyAccessInfo::kNotFound:
__ LoadRoot(result_reg, RootIndex::kUndefinedValue);
@ -962,36 +956,60 @@ void LoadPolymorphicTaggedField::GenerateCode(MaglevAssembler* masm,
}
case compiler::PropertyAccessInfo::kDataField:
case compiler::PropertyAccessInfo::kFastDataConstant: {
// TODO(victorgomes): Support ConstantDataFields.
Register load_source = object;
// Resolve property holder.
if (access_info.holder().has_value()) {
load_source = object_map; // Reuse scratch.
__ Move(load_source, access_info.holder().value().object());
}
FieldIndex field_index = access_info.field_index();
if (!field_index.is_inobject()) {
Register load_source_object = load_source;
if (load_source == object) {
load_source = object_map; // Reuse scratch.
}
// The field is in the property array, first load it from there.
__ AssertNotSmi(load_source_object);
__ DecompressAnyTagged(
load_source,
FieldMemOperand(load_source_object,
JSReceiver::kPropertiesOrHashOffset));
}
__ AssertNotSmi(load_source);
__ DecompressAnyTagged(
result_reg, FieldMemOperand(load_source, field_index.offset()));
__ LoadDataField(access_info, result_reg, object, object_map);
break;
}
default:
UNREACHABLE();
}
__ Jump(&done);
__ bind(&next);
}
// A HeapNumberMap was not found, we should eager deopt here in case of a
// number.
if (!is_number.is_bound()) {
__ bind(&is_number);
}
// No map matched!
__ EmitEagerDeopt(this, DeoptimizeReason::kWrongMap);
__ bind(&done);
}
void LoadPolymorphicDoubleField::SetValueLocationConstraints() {
UseRegister(object_input());
DefineAsRegister(this);
set_temporaries_needed(1);
}
void LoadPolymorphicDoubleField::GenerateCode(MaglevAssembler* masm,
const ProcessingState& state) {
MaglevAssembler::ScratchRegisterScope temps(masm);
Register object = ToRegister(object_input());
Register scratch = temps.Acquire();
Label done;
Label is_number;
Condition is_smi = __ CheckSmi(object);
__ JumpIf(is_smi, &is_number);
__ LoadMap(scratch, object);
for (const compiler::PropertyAccessInfo& access_info : access_infos_) {
Label next;
__ CheckMaps(access_info.lookup_start_object_maps(), scratch, &is_number,
&next);
__ LoadDataField(access_info, scratch, object, scratch);
switch (access_info.field_representation().kind()) {
case Representation::kSmi:
__ SmiToDouble(ToDoubleRegister(result()), scratch);
break;
case Representation::kDouble:
__ LoadHeapNumberValue(ToDoubleRegister(result()), scratch);
break;
default:
UNREACHABLE();
}
__ Jump(&done);
__ bind(&next);
}

View File

@ -161,6 +161,7 @@ class CompactInterpreterFrameState;
V(GetSecondReturnedValue) \
V(GetTemplateObject) \
V(InitialValue) \
V(LoadPolymorphicDoubleField) \
V(LoadPolymorphicTaggedField) \
V(LoadTaggedField) \
V(LoadDoubleField) \
@ -4062,6 +4063,32 @@ class LoadPolymorphicTaggedField
ZoneVector<compiler::PropertyAccessInfo> access_infos_;
};
class LoadPolymorphicDoubleField
: public FixedInputValueNodeT<1, LoadPolymorphicDoubleField> {
using Base = FixedInputValueNodeT<1, LoadPolymorphicDoubleField>;
public:
explicit LoadPolymorphicDoubleField(
uint64_t bitfield, ZoneVector<compiler::PropertyAccessInfo>&& access_info)
: Base(bitfield), access_infos_(access_info) {}
static constexpr OpProperties kProperties = OpProperties::Reading() |
OpProperties::EagerDeopt() |
OpProperties::Float64();
static constexpr
typename Base::InputTypes kInputTypes{ValueRepresentation::kTagged};
static constexpr int kObjectIndex = 0;
Input& object_input() { return input(kObjectIndex); }
void SetValueLocationConstraints();
void GenerateCode(MaglevAssembler*, const ProcessingState&);
void PrintParams(std::ostream&, MaglevGraphLabeller*) const {}
private:
ZoneVector<compiler::PropertyAccessInfo> access_infos_;
};
class LoadTaggedField : public FixedInputValueNodeT<1, LoadTaggedField> {
using Base = FixedInputValueNodeT<1, LoadTaggedField>;

View File

@ -424,6 +424,17 @@ inline void MaglevAssembler::JumpIfTaggedEqual(Register r1, Register r2,
j(equal, target, distance);
}
inline void MaglevAssembler::LoadHeapNumberValue(DoubleRegister result,
Register heap_number) {
Movsd(result, FieldOperand(heap_number, HeapNumber::kValueOffset));
}
inline void MaglevAssembler::SmiToDouble(DoubleRegister result, Register smi) {
AssertSmi(smi);
SmiUntag(smi);
Cvtlsi2sd(result, smi);
}
inline void MaglevAssembler::Pop(Register dst) { MacroAssembler::Pop(dst); }
template <typename NodeT>

View File

@ -785,23 +785,6 @@ void BuiltinStringPrototypeCharCodeAt::GenerateCode(
__ bind(*done);
}
void LoadDoubleField::SetValueLocationConstraints() {
UseRegister(object_input());
DefineAsRegister(this);
set_temporaries_needed(1);
}
void LoadDoubleField::GenerateCode(MaglevAssembler* masm,
const ProcessingState& state) {
MaglevAssembler::ScratchRegisterScope temps(masm);
Register tmp = temps.Acquire();
Register object = ToRegister(object_input());
__ AssertNotSmi(object);
__ DecompressAnyTagged(tmp, FieldOperand(object, offset()));
__ AssertNotSmi(tmp);
__ Movsd(ToDoubleRegister(result()),
FieldOperand(tmp, HeapNumber::kValueOffset));
}
void LoadFixedArrayElement::SetValueLocationConstraints() {
UseRegister(elements_input());
UseRegister(index_input());