28bool IsFresh(Node* node) {
29 return node->opcode() == IrOpcode::kAllocate ||
30 node->opcode() == IrOpcode::kAllocateRaw;
33bool IsConstant(Node* node) {
34 return node->opcode() == IrOpcode::kParameter ||
35 node->opcode() == IrOpcode::kHeapConstant;
38bool MayAlias(Node* lhs, Node* rhs) {
39 if (lhs == rhs)
return true;
41 (IsFresh(lhs) && IsConstant(rhs)) || (IsConstant(lhs) && IsFresh(rhs))) {
47Node* ResolveAliases(Node* node) {
48 while (node->opcode() == IrOpcode::kWasmTypeCast ||
49 node->opcode() == IrOpcode::kWasmTypeCastAbstract ||
50 node->opcode() == IrOpcode::kAssertNotNull ||
51 node->opcode() == IrOpcode::kTypeGuard) {
59constexpr int kArrayLengthFieldIndex = -1;
60constexpr int kStringPrepareForGetCodeunitIndex = -2;
61constexpr int kStringAsWtf16Index = -3;
62constexpr int kAnyConvertExternIndex = -4;
70 if (state != original) {
71 if (original ==
nullptr || !state->
Equals(original)) {
88 jsgraph()->Int32Constant(shift)),
89 jsgraph()->Int32Constant(shift));
103 return {
value, effect};
107 if (!value_type.IsWasm()) {
108 return {
value, effect};
130 return {
value, effect};
136 if (
v8_flags.trace_turbo_load_elimination) {
139 switch (node->opcode()) {
140 case IrOpcode::kWasmStructGet:
142 case IrOpcode::kWasmStructSet:
144 case IrOpcode::kWasmArrayLength:
146 case IrOpcode::kWasmArrayInitializeLength:
148 case IrOpcode::kStringPrepareForGetCodeunit:
150 case IrOpcode::kStringAsWtf16:
152 case IrOpcode::kWasmAnyConvertExtern:
154 case IrOpcode::kEffectPhi:
156 case IrOpcode::kDead:
158 case IrOpcode::kStart:
166 DCHECK_EQ(node->opcode(), IrOpcode::kWasmStructGet);
168 Node*
object = ResolveAliases(input_struct);
172 if (object->opcode() == IrOpcode::kDead)
return NoChange();
174 if (state ==
nullptr)
return NoChange();
177 bool is_mutable = field_info.type->mutability(field_info.field_index);
200 !(is_mutable ? state->immutable_state : state->mutable_state)
201 .LookupField(field_info.field_index,
object)
207 return Replace(
dead());
214 is_mutable ? &state->mutable_state : &state->immutable_state;
217 half_state->
LookupField(field_info.field_index,
object);
221 lookup_result.
value, effect, control,
222 field_info.
type->field(field_info.field_index), field_info.is_signed);
223 if (std::get<0>(replacement) ==
dead()) {
230 return Replace(
dead());
232 ReplaceWithValue(node, std::get<0>(replacement), std::get<1>(replacement),
235 return Replace(std::get<0>(replacement));
238 half_state = half_state->
AddField(field_info.field_index,
object, node);
249 DCHECK_EQ(node->opcode(), IrOpcode::kWasmStructSet);
251 Node*
object = ResolveAliases(input_struct);
256 if (object->opcode() == IrOpcode::kDead)
return NoChange();
258 if (state ==
nullptr)
return NoChange();
282 bool is_mutable = field_info.type->mutability(field_info.field_index);
290 !(is_mutable ? state->immutable_state : state->mutable_state)
291 .LookupField(field_info.field_index,
object)
297 return Replace(
dead());
302 state->mutable_state.
KillField(field_info.field_index,
object);
304 mutable_state->
AddField(field_info.field_index,
object, value);
310 DCHECK(state->immutable_state.LookupField(field_info.field_index,
object)
313 state->immutable_state.
AddField(field_info.field_index,
object, value);
329 if (object->opcode() == IrOpcode::kDead)
return NoChange();
331 if (state ==
nullptr)
return NoChange();
333 HalfState const* immutable_state = &state->immutable_state;
339 ReplaceWithValue(node, lookup_result.
value, effect, control);
341 return Replace(lookup_result.
value);
344 immutable_state = immutable_state->
AddField(index,
object, node);
353 DCHECK_EQ(node->opcode(), IrOpcode::kWasmArrayLength);
358 DCHECK_EQ(node->opcode(), IrOpcode::kWasmArrayInitializeLength);
363 if (object->opcode() == IrOpcode::kDead)
return NoChange();
365 if (state ==
nullptr)
return NoChange();
368 DCHECK(state->immutable_state.LookupField(kArrayLengthFieldIndex,
object)
371 state->immutable_state.
AddField(kArrayLengthFieldIndex,
object, value);
378 DCHECK_EQ(node->opcode(), IrOpcode::kStringPrepareForGetCodeunit);
383 if (object->opcode() == IrOpcode::kDead)
return NoChange();
385 if (state ==
nullptr)
return NoChange();
387 HalfState const* mutable_state = &state->mutable_state;
390 mutable_state->
LookupField(kStringPrepareForGetCodeunitIndex,
object);
393 for (
size_t i : {0, 1, 2}) {
395 ReplaceWithValue(proj_to_replace,
397 proj_to_replace->
Kill();
399 ReplaceWithValue(node, lookup_result.
value, effect, control);
401 return Replace(lookup_result.
value);
405 mutable_state->
AddField(kStringPrepareForGetCodeunitIndex,
object, node);
414 DCHECK_EQ(node->opcode(), IrOpcode::kStringAsWtf16);
419 DCHECK_EQ(node->opcode(), IrOpcode::kWasmAnyConvertExtern);
427 if (node->op()->EffectOutputCount() == 0)
return NoChange();
428 DCHECK_EQ(node->op()->EffectInputCount(), 1);
434 if (state ==
nullptr)
return NoChange();
442 return UpdateState(node, node->opcode() == IrOpcode::kCall &&
444 ?
zone()->New<AbstractState>(
454 DCHECK_EQ(node->opcode(), IrOpcode::kEffectPhi);
458 if (state0 ==
nullptr)
return NoChange();
459 if (control->
opcode() == IrOpcode::kLoop) {
469 int const input_count = node->op()->EffectInputCount();
470 for (
int i = 1;
i < input_count; ++
i) {
472 if (
node_states_.Get(effect) ==
nullptr)
return NoChange();
480 for (
int i = 1;
i < input_count; ++
i) {
491 Node*
object)
const {
496 int field_index,
Node*
object,
Node* value)
const {
503 int field_index,
Node*
object)
const {
504 const InnerMap& same_index_map = fields_.
Get(field_index);
506 for (std::pair<Node*, FieldOrElementValue> pair : same_index_map) {
507 if (MayAlias(pair.first,
object)) {
518 DCHECK_EQ(node->opcode(), IrOpcode::kEffectPhi);
519 if (state->mutable_state.IsEmpty())
return state;
520 std::queue<Node*> queue;
524 visited.insert(node);
525 for (
int i = 1;
i < node->InputCount() - 1; ++
i) {
526 queue.push(node->InputAt(
i));
528 while (!queue.empty()) {
529 Node*
const current = queue.front();
531 if (visited.insert(current).second) {
532 if (current->opcode() == IrOpcode::kWasmStructSet) {
534 if (object->opcode() == IrOpcode::kDead ||
535 object->opcode() == IrOpcode::kDeadValue) {
538 state->immutable_state);
541 bool is_mutable = field_info.type->mutability(field_info.field_index);
544 state->mutable_state.
KillField(field_info.field_index,
object);
546 state->immutable_state);
550 }
else if (current->opcode() == IrOpcode::kCall &&
553 state->immutable_state);
555 for (
int i = 0;
i < current->op()->EffectInputCount(); ++
i) {
565 for (
const std::pair<int, InnerMap> to_map : fields_) {
566 InnerMap to_map_copy(to_map.second);
567 int key = to_map.first;
569 for (std::pair<Node*, FieldOrElementValue> value : to_map.second) {
570 if (current_map.
Get(value.first) != value.second) {
571 to_map_copy.
Set(value.first, empty);
574 fields_.Set(
key, to_map_copy);
Isolate * isolate() const
CommonOperatorBuilder * common() const
MachineOperatorBuilder * machine() const
static Type GetType(const Node *node)
static bool IsTyped(const Node *node)
static Node * GetEffectInput(Node *node, int index=0)
static Node * GetValueInput(Node *node, int index)
static void SetType(Node *node, Type type)
static Node * FindProjection(Node *node, size_t projection_index)
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)
void IntersectWith(HalfState const *that)
HalfState const * AddField(int field_index, Node *object, Node *value) const
HalfState const * KillField(int field_index, Node *object) const
FieldOrElementValue LookupField(int field_index, Node *object) const
Isolate * isolate() const
JSGraph * jsgraph() const
Reduction ReduceStringPrepareForGetCodeunit(Node *node)
NodeAuxData< AbstractState const * > node_states_
Reduction ReduceEffectPhi(Node *node)
MachineOperatorBuilder * machine() const
Reduction ReduceWasmStructGet(Node *node)
Reduction ReduceStart(Node *node)
Reduction ReduceStringAsWtf16(Node *node)
Reduction ReduceOtherNode(Node *node)
Reduction ReduceWasmStructSet(Node *node)
CommonOperatorBuilder * common() const
WasmLoadElimination(Editor *editor, JSGraph *jsgraph, Zone *zone)
Reduction Reduce(Node *node) final
Reduction ReduceAnyConvertExtern(Node *node)
AbstractState const * ComputeLoopState(Node *node, AbstractState const *state) const
Reduction ReduceLoadLikeFromImmutable(Node *node, int index)
Reduction UpdateState(Node *node, AbstractState const *state)
AbstractState const empty_state_
std::tuple< Node *, Node * > TruncateAndExtendOrType(Node *value, Node *effect, Node *control, wasm::ValueType field_type, bool is_signed)
Reduction ReduceWasmArrayInitializeLength(Node *node)
AbstractState const * empty_state() const
Reduction ReduceWasmArrayLength(Node *node)
constexpr int value_kind_size() const
constexpr bool is_uninhabited() const
ZoneVector< RpoNumber > & result
LiftoffAssembler::CacheState state
T const & OpParameter(const Operator *op)
constexpr IndependentHeapType kWasmNullRef
constexpr IndependentValueType kWasmI8
V8_INLINE bool IsSubtypeOf(ValueType subtype, ValueType supertype, const WasmModule *sub_module, const WasmModule *super_module)
V8_INLINE bool TypesUnrelated(ValueType type1, ValueType type2, const WasmModule *module1, const WasmModule *module2)
constexpr IndependentValueType kWasmI16
V8_EXPORT_PRIVATE FlagValues v8_flags
bool is_signed(Condition cond)
#define DCHECK(condition)
#define DCHECK_LT(v1, v2)
#define DCHECK_EQ(v1, v2)
bool Equals(AbstractState const *that) const
const WasmModule * module