[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:
parent
a0417c29d8
commit
cca14c7834
@ -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() {
|
||||
|
@ -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());
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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>;
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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());
|
||||
|
Loading…
Reference in New Issue
Block a user