23#define TRACE_UNTAGGING(...) \
25 if (v8_flags.trace_maglev_phi_untagging) { \
26 StdoutStream{} << __VA_ARGS__ << std::endl; \
35 if (block->has_phi()) {
36 auto& phis = *block->phis();
38 auto first_retry = phis.begin();
39 auto end_retry = first_retry;
40 bool any_change =
false;
42 for (
auto it = phis.begin(); it != phis.end(); ++it) {
51 if (end_retry == first_retry) {
61 for (
auto it = first_retry; it != end_retry; ++it) {
71 if (block->successors().size() != 1)
return false;
84 if (node->is_exception_phi()) {
100 bool has_tagged_phi_input =
false;
101 for (
int i = 0;
i < node->input_count();
i++) {
109 if (constant->object().IsHeapNumber()) {
118 }
else if (input->properties().is_conversion()) {
126 input->input(0).node()->properties().value_representation());
127 }
else if (
Phi* input_phi = input->TryCast<
Phi>()) {
129 input_reprs.
Add(input_phi->value_representation());
132 if (node->is_backedge_offset(
i) &&
133 node->merge_state()->is_loop_with_peeled_iteration()) {
141 has_tagged_phi_input =
true;
151 v8_flags.maglev_hoist_osr_value_phi_untagging &&
157 if (node->is_loop_phi() && !node->is_backedge_offset(
i)) {
162 if (
NodeTypeIs(static_type, NodeType::kSmi)) {
167 if (
NodeTypeIs(static_type, NodeType::kNumber)) {
178 if (
v8_flags.maglev_speculative_hoist_phi_untagging) {
182 DCHECK(!node->merge_state()->is_resumable_loop());
206 if (node->is_loop_phi() && !node->get_same_loop_uses_repr_hints().empty()) {
209 use_reprs = node->get_same_loop_uses_repr_hints();
210 TRACE_UNTAGGING(
" + use_reprs : " << use_reprs <<
" (same loop only)");
212 use_reprs = node->get_uses_repr_hints();
229 return default_result;
234 input_reprs.
empty()) {
237 return default_result;
295 use_reprs.
is_subset_of({UseRepresentation::kHoleyFloat64,
296 UseRepresentation::kTruncatedInt32}));
305 if (hoist_untagging.
size() && node->uses_require_31_bit_value()) {
308 return default_result;
311 auto intersection = possible_inputs & allowed_inputs_for_uses;
316 UseRepresentation::kInt32, UseRepresentation::kTruncatedInt32})) {
331 DCHECK(intersection.empty());
335 return default_result;
345 const int skip_backedge = phi->is_loop_phi() ? 1 : 0;
346 for (
int i = 0;
i < phi->input_count() - skip_backedge;
i++) {
348 if (
Phi* phi_input = input->TryCast<
Phi>()) {
355 DCHECK(input->is_tagged());
371 return Opcode::kCheckedInt32ToUint32;
374 return Opcode::kChangeInt32ToFloat64;
384 return Opcode::kCheckedUint32ToInt32;
388 return Opcode::kChangeUint32ToFloat64;
399 return Opcode::kTruncateFloat64ToInt32;
401 return Opcode::kCheckedTruncateFloat64ToInt32;
407 return Opcode::kIdentity;
419 return Opcode::kTruncateFloat64ToInt32;
421 return Opcode::kCheckedTruncateFloat64ToInt32;
427 return Opcode::kHoleyFloat64ToMaybeNanFloat64;
450 phi->change_representation(repr);
453 phi->InitializeRegisterData();
455 for (
int input_index = 0; input_index < phi->input_count(); input_index++) {
457#define TRACE_INPUT_LABEL \
458 " @ Input " << input_index << " (" \
459 << PrintNodeLabel(graph_labeller(), input) << ")"
465 phi->change_input(input_index,
472 <<
": Making Float64 instead of Smi");
473 phi->change_input(input_index,
484 <<
": Making Float64 instead of Constant");
485 DCHECK(constant->object().IsHeapNumber());
488 phi->change_input(input_index,
490 constant->object().AsHeapNumber().value()));
491 }
else if (input->properties().is_conversion()) {
498 if (from_repr == repr) {
500 new_input = bypassed_input;
503 GetOpcodeForConversion(from_repr, repr,
false);
504 switch (conv_opcode) {
505 case Opcode::kChangeInt32ToFloat64: {
508 input, phi, input_index);
511 case Opcode::kChangeUint32ToFloat64: {
514 input, phi, input_index);
517 case Opcode::kIdentity:
519 new_input = bypassed_input;
526 }
else if (
Phi* input_phi = input->TryCast<
Phi>()) {
540 DCHECK(phi->merge_state()->is_loop_with_peeled_iteration());
541 DCHECK(phi->is_backedge_offset(input_index));
543 DeoptFrame* deopt_frame = phi->merge_state()->backedge_deopt_frame();
550 phi->predecessor_at(input_index),
561 phi->predecessor_at(input_index), deopt_frame));
571 phi->predecessor_at(input_index), deopt_frame));
580 <<
": Eagerly untagging Phi on backedge");
581 }
else if (from_repr != repr &&
588 phi->change_input(input_index,
591 phi->predecessor_at(input_index)));
594 <<
": Converting phi input with a ChangeInt32ToFloat64");
601 <<
": Keeping untagged Phi input as-is");
608 return &block->control_node()
613 switch (hoist_untagging[input_index]) {
615 block = phi->merge_state()->predecessor_at(input_index);
616 deopt_frame =
nullptr;
619 block = phi->merge_state()->predecessor_at(input_index);
620 deopt_frame = GetDeoptFrame(block);
624 deopt_frame = GetDeoptFrame(block);
631 (phi->is_loop_phi() && !phi->is_backedge_offset(input_index)));
669 DCHECK(!phi->uses_require_31_bit_value());
696template <
class NodeT>
700 <<
": Replacing old conversion with a ChangeInt32ToFloat64");
708 case Opcode::kCheckedSmiUntag:
709 case Opcode::kUnsafeSmiUntag:
710 case Opcode::kCheckedNumberToInt32:
711 case Opcode::kCheckedObjectToIndex:
712 case Opcode::kCheckedTruncateNumberOrOddballToInt32:
713 case Opcode::kTruncateNumberOrOddballToInt32:
714 case Opcode::kCheckedNumberOrOddballToFloat64:
715 case Opcode::kUncheckedNumberOrOddballToFloat64:
716 case Opcode::kCheckedNumberOrOddballToHoleyFloat64:
744 if (from_repr == to_repr) {
746 if (phi->uses_require_31_bit_value() &&
763 old_untagging->
OverwriteWith<UnsafeTruncateFloat64ToInt32>();
780 bool conversion_is_truncating_float64 =
784 Opcode needed_conversion = GetOpcodeForConversion(
785 from_repr, to_repr, conversion_is_truncating_float64);
790 number_untagging->conversion_type() !=
794 needed_conversion = Opcode::kCheckedHoleyFloat64ToFloat64;
798 if (needed_conversion != old_untagging->
opcode()) {
807 switch (phi->value_representation()) {
833 switch (phi->value_representation()) {
854 if (diff == 0)
return;
855 size_t old_size = block->nodes().size();
857 auto begin = block->nodes().begin();
858 std::copy_backward(begin, begin + old_size, block->nodes().end());
938 switch (phi->value_representation()) {
962 if (node->properties().is_conversion()) {
971 DCHECK_NE(new_nodes_.find(node), new_nodes_.end());
991 if (phi->has_key()) {
992 if (predecessor_index.has_value()) {
994 phi->key(), predecessor_index.value())) {
1006 switch (phi->value_representation()) {
1038 if (predecessor_index.has_value()) {
1043 block->
is_loop() && block->successors().size() == 1 &&
1044 block->successors().at(0) == block);
1048 if (phi->has_key()) {
1063 if (!block->has_phi())
return;
1064 for (
Phi* phi : *block->phis()) {
1065 int last_input_idx = phi->input_count() - 1;
1095 phi->value_representation()) ||
1098 phi->value_representation() ==
1100 phi->change_input(last_input_idx, backedge->
input(0).
node());
1115 if (node->properties().can_eager_deopt()) {
1117 node->SetEagerDeoptInfo(
builder_->
zone(), *deopt_frame);
1128 block->nodes().push_back(node);
1140 new_nodes_.insert(node);
1160 int skip_backedge = new_block->
is_loop();
1167 auto merge_taggings =
1170 if (node ==
nullptr) {
1177 return static_cast<Phi*
>(
nullptr);
1188 for (
int i = 0;
static_cast<size_t>(
i) < predecessors.
size();
i++) {
1189 phi->set_input(
i, predecessors[
i]);
1191 if (predecessors.size() !=
static_cast<size_t>(predecessor_count)) {
1195 phi->set_input(predecessor_count - 1, phi);
constexpr bool is_subset_of(EnumSet set) const
constexpr void Add(E element)
constexpr bool contains_only(E element) const
constexpr bool empty() const
constexpr bool contains_any(EnumSet set) const
constexpr void RemoveAll()
constexpr bool contains(E element) const
void resize(size_t new_size)
V8_INLINE constexpr int32_t value() const
void resize(size_t new_size)
void push_back(const T &value)
Key NewKey(KeyData data, Value initial_value=Value{})
const Value & Get(Key key) const
const Value & GetPredecessorValue(Key key, int predecessor_index)
void StartNewSnapshot(base::Vector< const Snapshot > predecessors, const ChangeCallback &change_callback={})
bool Set(Key key, Value new_value)
void AddPhi(Phi *phi) const
base::SmallVector< BasicBlock *, 2 > successors() const
bool is_merge_block() const
BasicBlock * predecessor_at(int i) const
ControlNode * control_node() const
BasicBlock * predecessor() const
int predecessor_count() const
MergePointInterpreterFrameState * state() const
BlockConstIterator begin() const
MaglevGraphLabeller * graph_labeller() const
LocalIsolate * local_isolate() const
Float64Constant * GetFloat64Constant(double constant)
bool has_graph_labeller() const
compiler::JSHeapBroker * broker() const
Int32Constant * GetInt32Constant(int32_t constant)
void RegisterNode(const NodeBase *node, const MaglevCompilationUnit *unit, BytecodeOffset bytecode_offset, SourcePosition position)
MaglevGraphBuilder * builder_
void UpdateUntaggingOfPhi(Phi *phi, ValueNode *old_untagging)
SnapshotTable< ValueNode * > phi_taggings_
void EnsurePhiInputsTagged(Phi *phi)
BasicBlock * current_block_
ValueNode * EnsurePhiTagged(Phi *phi, BasicBlock *block, NewNodePosition pos, const ProcessingState *state, std::optional< int > predecessor_index=std::nullopt)
void RegisterNewNode(ValueNode *node)
void ConvertTaggedPhiTo(Phi *phi, ValueRepresentation repr, const HoistTypeList &hoist_untagging)
ValueNode * AddNode(ValueNode *node, BasicBlock *block, NewNodePosition pos, const ProcessingState *state, DeoptFrame *deopt_frame=nullptr)
void FixLoopPhisBackedge(BasicBlock *block)
ZoneVector< Snapshot > predecessors_
void PreparePhiTaggings(BasicBlock *old_block, const BasicBlock *new_block)
@ kBeginingOfCurrentBlock
ZoneVector< Node * > new_nodes_at_start_
ProcessResult UpdateNodePhiInput(CheckSmi *node, Phi *phi, int input_index, const ProcessingState *state)
ProcessPhiResult ProcessPhi(Phi *node)
BlockProcessResult PreProcessBasicBlock(BasicBlock *block)
bool CanHoistUntaggingTo(BasicBlock *block)
void PostProcessBasicBlock(BasicBlock *block)
MaglevGraphLabeller * graph_labeller() const
absl::flat_hash_map< BasicBlock::Id, Snapshot > snapshots_
ValueNode * AddNodeAtBlockEnd(ValueNode *new_node, BasicBlock *block, DeoptFrame *deopt_frame=nullptr)
ValueNode * GetReplacementForPhiInputConversion(ValueNode *conversion_node, Phi *phi, uint32_t input_index)
bool IsUntagging(Opcode op)
bool is_resumable_loop() const
constexpr bool Is() const
void change_input(int index, ValueNode *node)
static Derived * New(Zone *zone, std::initializer_list< ValueNode * > inputs, Args &&... args)
constexpr Input & input(int index)
constexpr int input_count() const
constexpr Opcode opcode() const
Tagged< Smi > value() const
static constexpr int kElementsIndex
static constexpr int kIndexIndex
static constexpr int kValueIndex
static constexpr int kValueIndex
static constexpr int kElementsIndex
static constexpr int kIndexIndex
static constexpr int kValueIndex
static constexpr int kObjectIndex
static constexpr int kObjectIndex
static constexpr int kValueIndex
constexpr ValueRepresentation value_representation() const
#define TRACE_INPUT_LABEL
#define TRACE_UNTAGGING(...)
constexpr Vector< T > VectorOf(T *start, size_t size)
base::EnumSet< UseRepresentation, int8_t > UseRepresentationSet
base::EnumSet< ValueRepresentation, int8_t > ValueRepresentationSet
constexpr bool NodeTypeIs(NodeType type, NodeType to_check)
NodeType StaticTypeForNode(compiler::JSHeapBroker *broker, LocalIsolate *isolate, ValueNode *node)
V8_EXPORT_PRIVATE FlagValues v8_flags
constexpr bool SmiValuesAre32Bits()
#define DCHECK_NOT_NULL(val)
#define DCHECK_IMPLIES(v1, v2)
#define DCHECK_NE(v1, v2)
#define CHECK_EQ(lhs, rhs)
#define DCHECK(condition)
#define DCHECK_EQ(v1, v2)