17 if (
v8_flags.trace_turbo_load_elimination) {
18 if (node->op()->EffectInputCount() > 0) {
19 PrintF(
" visit #%d:%s", node->id(), node->op()->mnemonic());
20 if (node->op()->ValueInputCount() > 0) {
22 for (
int i = 0;
i < node->op()->ValueInputCount(); ++
i) {
25 PrintF(
"#%d:%s", value->id(), value->op()->mnemonic());
30 for (
int i = 0;
i < node->op()->EffectInputCount(); ++
i) {
33 PrintF(
" state[%i]: #%d:%s\n",
i, effect->
id(),
34 effect->op()->mnemonic());
35 state->mutable_state.Print();
36 state->immutable_state.Print();
38 PrintF(
" no state[%i]: #%d:%s\n",
i, effect->
id(),
39 effect->op()->mnemonic());
44 switch (node->opcode()) {
45 case IrOpcode::kLoadFromObject:
46 case IrOpcode::kLoadImmutableFromObject:
48 case IrOpcode::kStoreToObject:
49 case IrOpcode::kInitializeImmutableInObject:
51 case IrOpcode::kDebugBreak:
52 case IrOpcode::kAbortCSADcheck:
57 case IrOpcode::kEffectPhi:
61 case IrOpcode::kStart:
69namespace CsaLoadEliminationHelpers {
72 if (from == to)
return true;
81 return object->opcode() == IrOpcode::kParameter ||
82 object->opcode() == IrOpcode::kLoadImmutable ||
87 return object->opcode() == IrOpcode::kAllocate ||
88 object->opcode() == IrOpcode::kAllocateRaw;
93namespace Helpers = CsaLoadEliminationHelpers;
96template <
typename OuterKey>
100 for (
const std::pair<OuterKey, InnerMap>& to_map : to) {
101 InnerMap to_map_copy(to_map.second);
102 OuterKey
key = to_map.first;
104 for (std::pair<Node*, FieldInfo> info : to_map.second) {
105 if (current_map.
Get(info.first) != info.second) {
106 to_map_copy.
Set(info.first, empty_info);
109 to.Set(
key, to_map_copy);
114 IntersectWith(fresh_entries_, that->fresh_entries_);
115 IntersectWith(constant_entries_, that->constant_entries_);
116 IntersectWith(arbitrary_entries_, that->arbitrary_entries_);
117 IntersectWith(fresh_unknown_entries_, that->fresh_unknown_entries_);
118 IntersectWith(constant_unknown_entries_, that->constant_unknown_entries_);
119 IntersectWith(arbitrary_unknown_entries_, that->arbitrary_unknown_entries_);
127 if (
m.HasResolvedValue()) {
128 uint32_t num_offset =
static_cast<uint32_t
>(
m.ResolvedValue());
135 result->KillOffsetInFresh(
object, num_offset, repr);
136 KillOffset(
result->arbitrary_entries_, num_offset, repr,
zone_);
138 result->arbitrary_unknown_entries_ = empty_unknown;
143 KillOffset(
result->constant_entries_, num_offset, repr,
zone_);
144 KillOffset(
result->arbitrary_entries_, num_offset, repr,
zone_);
145 result->constant_unknown_entries_ = empty_unknown;
146 result->arbitrary_unknown_entries_ = empty_unknown;
150 KillOffset(
result->fresh_entries_, num_offset, repr,
zone_);
151 KillOffset(
result->constant_entries_, num_offset, repr,
zone_);
152 KillOffset(
result->arbitrary_entries_, num_offset, repr,
zone_);
153 result->fresh_unknown_entries_ = empty_unknown;
154 result->constant_unknown_entries_ = empty_unknown;
155 result->arbitrary_unknown_entries_ = empty_unknown;
163 for (
auto map :
result->fresh_entries_) {
168 result->fresh_entries_.Set(map.first, map_copy);
171 result->arbitrary_entries_ = empty_constant;
172 result->arbitrary_unknown_entries_ = empty_unknown;
176 result->constant_entries_ = empty_constant;
177 result->constant_unknown_entries_ = empty_unknown;
178 result->arbitrary_entries_ = empty_constant;
179 result->arbitrary_unknown_entries_ = empty_unknown;
193 if (
m.HasResolvedValue()) {
194 uint32_t offset_num =
static_cast<uint32_t
>(
m.ResolvedValue());
200 Update(infos, offset_num,
object,
FieldInfo(value, repr));
216 if (
m.HasResolvedValue()) {
217 uint32_t num_offset =
static_cast<uint32_t
>(
m.ResolvedValue());
222 : arbitrary_entries_;
223 return infos.
Get(num_offset).Get(
object);
226 ? fresh_unknown_entries_
228 ? constant_unknown_entries_
229 : arbitrary_unknown_entries_;
258 for (uint32_t
i = initial_offset;
i <
offset;
i++) {
260 for (
const std::pair<Node*, FieldInfo> info : infos.
Get(
i)) {
263 static_cast<int>(
offset -
i)) {
264 map_copy.
Set(info.first, {});
267 infos.
Set(
i, map_copy);
274 Update(fresh_entries_,
offset +
i,
object, {});
279 for (uint32_t
i = initial_offset;
i <
offset;
i++) {
280 const FieldInfo& info = fresh_entries_.Get(
i).Get(
object);
283 static_cast<int>(
offset -
i)) {
284 Update(fresh_entries_,
i,
object, {});
292 for (
const auto outer_entry : infos) {
293 for (
const auto inner_entry : outer_entry.second) {
294 Node*
object = inner_entry.first;
295 uint32_t
offset = outer_entry.first;
297 PrintF(
" #%d:%s+(%d) -> #%d:%s [repr=%s]\n", object->id(),
298 object->op()->mnemonic(),
offset, info.value->id(),
299 info.value->op()->mnemonic(),
308 for (
const auto outer_entry : infos) {
309 for (
const auto inner_entry : outer_entry.second) {
310 Node*
object = outer_entry.first;
313 PrintF(
" #%d:%s+#%d:%s -> #%d:%s [repr=%s]\n", object->id(),
314 object->op()->mnemonic(),
offset->id(),
offset->op()->mnemonic(),
315 info.value->id(), info.value->op()->mnemonic(),
322 Print(fresh_entries_);
323 Print(constant_entries_);
324 Print(arbitrary_entries_);
325 Print(fresh_unknown_entries_);
326 Print(constant_unknown_entries_);
327 Print(arbitrary_unknown_entries_);
340 return Replace(unreachable);
345 DCHECK(node->opcode() == IrOpcode::kLoadFromObject ||
346 node->opcode() == IrOpcode::kLoadImmutableFromObject);
351 if (state ==
nullptr)
return NoChange();
352 bool is_mutable = node->opcode() == IrOpcode::kLoadFromObject;
354 if (!(is_mutable ? &state->immutable_state : &state->mutable_state)
360 auto rep =
ObjectAccessOf(node->op()).machine_type.representation();
363 ReplaceWithValue(node, dead_value, unreachable, control);
365 return Replace(dead_value);
368 is_mutable ? &state->mutable_state : &state->immutable_state;
372 if (!lookup_result.
IsEmpty()) {
380 ReplaceWithValue(node, replacement, effect);
384 return Replace(replacement);
387 half_state = half_state->
AddField(
object,
offset, node, representation);
399 DCHECK(node->opcode() == IrOpcode::kStoreToObject ||
400 node->opcode() == IrOpcode::kInitializeImmutableInObject);
406 if (state ==
nullptr)
return NoChange();
408 if (node->opcode() == IrOpcode::kStoreToObject) {
410 if (!(state->immutable_state.Lookup(
object,
offset).IsEmpty())) {
415 mutable_state = mutable_state->
AddField(
object,
offset, value, repr);
421 if (!(state->mutable_state.Lookup(
object,
offset).IsEmpty())) {
425 DCHECK(state->immutable_state.Lookup(
object,
offset).IsEmpty());
438 if (state0 ==
nullptr)
return NoChange();
439 if (control->
opcode() == IrOpcode::kLoop) {
449 int const input_count = node->op()->EffectInputCount();
450 for (
int i = 1;
i < input_count; ++
i) {
452 if (
node_states_.Get(effect) ==
nullptr)
return NoChange();
460 for (
int i = 1;
i < input_count; ++
i) {
474 if (
m.Is(ExternalReference::check_object_type())) {
481 if (node->op()->EffectInputCount() == 1 &&
482 node->op()->EffectOutputCount() == 1) {
488 if (state ==
nullptr)
return NoChange();
496 state->immutable_state));
498 DCHECK_EQ(0, node->op()->EffectOutputCount());
507 if (state != original) {
508 if (original ==
nullptr || !state->
Equals(original)) {
510 return Changed(node);
519 if (state ==
nullptr)
return NoChange();
525 DCHECK_EQ(node->opcode(), IrOpcode::kEffectPhi);
526 std::queue<Node*> queue;
527 std::unordered_set<Node*> visited;
528 visited.insert(node);
529 for (
int i = 1;
i < node->InputCount() - 1; ++
i) {
530 queue.push(node->InputAt(
i));
532 while (!queue.empty()) {
533 Node*
const current = queue.front();
535 if (visited.insert(current).second) {
536 if (current->opcode() == IrOpcode::kStoreToObject) {
544 state->immutable_state);
545 }
else if (current->opcode() == IrOpcode::kInitializeImmutableInObject) {
550 CHECK(state->immutable_state.Lookup(
object,
offset).IsEmpty());
554 state->immutable_state);
556 for (
int i = 0;
i < current->op()->EffectInputCount(); ++
i) {
582 jsgraph()->Int32Constant(shift)),
583 jsgraph()->Int32Constant(shift));
600 DCHECK((from == to.representation() &&
static constexpr MachineType Uint8()
static constexpr MachineType Uint16()
static constexpr MachineType Int16()
static constexpr MachineType Int8()
ConstantOffsetInfos arbitrary_entries_
UnknownOffsetInfos fresh_unknown_entries_
HalfState const * KillField(Node *object, Node *offset, MachineRepresentation repr) const
ConstantOffsetInfos fresh_entries_
ConstantOffsetInfos constant_entries_
static void KillOffset(ConstantOffsetInfos &infos, uint32_t offset, MachineRepresentation repr, Zone *zone)
UnknownOffsetInfos arbitrary_unknown_entries_
HalfState const * AddField(Node *object, Node *offset, Node *value, MachineRepresentation repr) const
void KillOffsetInFresh(Node *object, uint32_t offset, MachineRepresentation repr)
void IntersectWith(HalfState const *that)
UnknownOffsetInfos constant_unknown_entries_
FieldInfo Lookup(Node *object, Node *offset) const
Isolate * isolate() const
Reduction ReduceLoadFromObject(Node *node, ObjectAccess const &access)
AbstractState const * empty_state() const
Reduction PropagateInputState(Node *node)
CommonOperatorBuilder * common() const
Reduction ReduceOtherNode(Node *node)
Reduction ReduceStoreToObject(Node *node, ObjectAccess const &access)
JSGraph * jsgraph() const
Reduction ReduceCall(Node *node)
Reduction AssertUnreachable(Node *node)
Reduction ReduceStart(Node *node)
Reduction ReduceEffectPhi(Node *node)
Reduction Reduce(Node *node) final
NodeAuxData< AbstractState const * > node_states_
Reduction UpdateState(Node *node, AbstractState const *state)
MachineOperatorBuilder * machine() const
AbstractState const * ComputeLoopState(Node *node, AbstractState const *state) const
Node * TruncateAndExtend(Node *node, MachineRepresentation from, MachineType to)
Isolate * isolate() const
CommonOperatorBuilder * common() const
MachineOperatorBuilder * machine() const
static Node * GetEffectInput(Node *node, int index=0)
static Node * GetValueInput(Node *node, int index)
static bool IsConstant(Node *node)
static Node * GetControlInput(Node *node, int index=0)
constexpr IrOpcode::Value opcode() const
const Value & Get(const Key &key) const
void Set(Key key, Value value)
Node * NewNode(const Operator *op, int input_count, Node *const *inputs, bool incomplete=false)
ZoneVector< RpoNumber > & result
LiftoffAssembler::CacheState state
bool IsConstantObject(Node *object)
bool IsFreshObject(Node *object)
bool Subsumes(MachineRepresentation from, MachineRepresentation to)
const ObjectAccess & ObjectAccessOf(const Operator *op)
constexpr int kMaximumReprSizeInBytes
void PrintF(const char *format,...)
constexpr bool IsAnyTagged(MachineRepresentation rep)
void Print(Tagged< Object > obj)
const char * MachineReprToString(MachineRepresentation rep)
V8_EXPORT_PRIVATE FlagValues v8_flags
V8_EXPORT_PRIVATE constexpr int ElementSizeInBytes(MachineRepresentation)
constexpr bool IsIntegral(MachineRepresentation rep)
#define DCHECK_GE(v1, v2)
#define DCHECK(condition)
#define DCHECK_EQ(v1, v2)
bool Equals(AbstractState const *that) const
MachineRepresentation representation