| Index: src/compiler/simplified-lowering.cc
|
| diff --git a/src/compiler/simplified-lowering.cc b/src/compiler/simplified-lowering.cc
|
| index 0cc18584f70b694a1d4b72b42befbe2bb39a6f66..9d00d44e329a39d0e60ebd22722a85d33ef81b72 100644
|
| --- a/src/compiler/simplified-lowering.cc
|
| +++ b/src/compiler/simplified-lowering.cc
|
| @@ -154,6 +154,102 @@ UseInfo UseInfoForBasePointer(const ElementAccess& access) {
|
| return access.tag() != 0 ? UseInfo::AnyTagged() : UseInfo::PointerInt();
|
| }
|
|
|
| +
|
| +#ifdef DEBUG
|
| +// Helpers for monotonicity checking.
|
| +
|
| +bool MachineTypeIsSubtype(MachineType t1, MachineType t2) {
|
| + switch (t1) {
|
| + case kMachNone:
|
| + return true;
|
| + case kTypeBool:
|
| + return t2 == kTypeBool || t2 == kTypeNumber || t2 == kTypeAny;
|
| + case kTypeInt32:
|
| + return t2 == kTypeInt32 || t2 == kTypeNumber || t2 == kTypeAny;
|
| + case kTypeUint32:
|
| + return t2 == kTypeUint32 || t2 == kTypeNumber || t2 == kTypeAny;
|
| + case kTypeInt64:
|
| + return t2 == kTypeInt64;
|
| + case kTypeUint64:
|
| + return t2 == kTypeUint64;
|
| + case kTypeNumber:
|
| + return t2 == kTypeNumber || t2 == kTypeAny;
|
| + case kTypeAny:
|
| + return t2 == kTypeAny;
|
| + default:
|
| + break;
|
| + }
|
| + UNREACHABLE();
|
| + return false;
|
| +}
|
| +
|
| +
|
| +bool MachineRepresentationIsSubtype(MachineType r1, MachineType r2) {
|
| + switch (r1) {
|
| + case kMachNone:
|
| + return true;
|
| + case kRepBit:
|
| + return r2 == kRepBit || r2 == kRepTagged;
|
| + case kRepWord8:
|
| + return r2 == kRepWord8 || r2 == kRepWord16 || r2 == kRepWord32 ||
|
| + r2 == kRepWord64 || r2 == kRepFloat32 || r2 == kRepFloat64 ||
|
| + r2 == kRepTagged;
|
| + case kRepWord16:
|
| + return r2 == kRepWord16 || r2 == kRepWord32 || r2 == kRepWord64 ||
|
| + r2 == kRepFloat32 || r2 == kRepFloat64 || r2 == kRepTagged;
|
| + case kRepWord32:
|
| + return r2 == kRepWord32 || r2 == kRepWord64 || r2 == kRepFloat64 ||
|
| + r2 == kRepTagged;
|
| + case kRepWord64:
|
| + return r2 == kRepWord64;
|
| + case kRepFloat32:
|
| + return r2 == kRepFloat32 || r2 == kRepFloat64 || r2 == kRepTagged;
|
| + case kRepFloat64:
|
| + return r2 == kRepFloat64 || r2 == kRepTagged;
|
| + case kRepTagged:
|
| + return r2 == kRepTagged;
|
| + default:
|
| + break;
|
| + }
|
| + UNREACHABLE();
|
| + return false;
|
| +}
|
| +
|
| +
|
| +bool MachineTypeRepIsSubtype(MachineTypeUnion m1, MachineTypeUnion m2) {
|
| + return MachineTypeIsSubtype(static_cast<MachineType>(m1 & kTypeMask),
|
| + static_cast<MachineType>(m2 & kTypeMask)) &&
|
| + MachineRepresentationIsSubtype(
|
| + static_cast<MachineType>(m1 & kRepMask),
|
| + static_cast<MachineType>(m2 & kRepMask));
|
| +}
|
| +
|
| +
|
| +class InputUseInfos {
|
| + public:
|
| + explicit InputUseInfos(Zone* zone) : input_use_infos_(zone) {}
|
| +
|
| + void SetAndCheckInput(Node* node, int index, UseInfo use_info) {
|
| + if (input_use_infos_.empty()) {
|
| + input_use_infos_.resize(node->InputCount(), UseInfo::None());
|
| + }
|
| + // Check that the new use informatin is a super-type of the old
|
| + // one.
|
| + CHECK(IsUseLessGeneral(input_use_infos_[index], use_info));
|
| + input_use_infos_[index] = use_info;
|
| + }
|
| +
|
| + private:
|
| + ZoneVector<UseInfo> input_use_infos_;
|
| +
|
| + static bool IsUseLessGeneral(UseInfo use1, UseInfo use2) {
|
| + return MachineRepresentationIsSubtype(use1.preferred(), use2.preferred()) &&
|
| + use1.truncation().IsLessGeneralThan(use2.truncation());
|
| + }
|
| +};
|
| +
|
| +#endif // DEBUG
|
| +
|
| } // namespace
|
|
|
|
|
| @@ -191,19 +287,23 @@ class RepresentationSelector {
|
| : jsgraph_(jsgraph),
|
| count_(jsgraph->graph()->NodeCount()),
|
| info_(count_, zone),
|
| +#ifdef DEBUG
|
| + node_input_use_infos_(count_, InputUseInfos(zone), zone),
|
| +#endif
|
| nodes_(zone),
|
| replacements_(zone),
|
| phase_(PROPAGATE),
|
| changer_(changer),
|
| queue_(zone),
|
| source_positions_(source_positions),
|
| - type_cache_(TypeCache::Get()) {}
|
| + type_cache_(TypeCache::Get()) {
|
| + }
|
|
|
| void Run(SimplifiedLowering* lowering) {
|
| // Run propagation phase to a fixpoint.
|
| TRACE("--{Propagation phase}--\n");
|
| phase_ = PROPAGATE;
|
| - Enqueue(jsgraph_->graph()->end());
|
| + EnqueueInitial(jsgraph_->graph()->end());
|
| // Process nodes from the queue until it is empty.
|
| while (!queue_.empty()) {
|
| Node* node = queue_.front();
|
| @@ -245,11 +345,27 @@ class RepresentationSelector {
|
| }
|
| }
|
|
|
| - // Enqueue {node} if the {use} contains new information for that node.
|
| - // Add {node} to {nodes_} if this is the first time it's been visited.
|
| - void Enqueue(Node* node, UseInfo use_info = UseInfo::None()) {
|
| + void EnqueueInitial(Node* node) {
|
| + NodeInfo* info = GetInfo(node);
|
| + info->set_visited();
|
| + info->set_queued(true);
|
| + nodes_.push_back(node);
|
| + queue_.push(node);
|
| + }
|
| +
|
| + // Enqueue {use_node}'s {index} input if the {use} contains new information
|
| + // for that input node. Add the input to {nodes_} if this is the first time
|
| + // it's been visited.
|
| + void EnqueueInput(Node* use_node, int index,
|
| + UseInfo use_info = UseInfo::None()) {
|
| + Node* node = use_node->InputAt(index);
|
| if (phase_ != PROPAGATE) return;
|
| NodeInfo* info = GetInfo(node);
|
| +#ifdef DEBUG
|
| + // Check monotonicity of input requirements.
|
| + node_input_use_infos_[use_node->id()].SetAndCheckInput(use_node, index,
|
| + use_info);
|
| +#endif // DEBUG
|
| if (!info->visited()) {
|
| // First visit of this node.
|
| info->set_visited();
|
| @@ -284,7 +400,9 @@ class RepresentationSelector {
|
| // instruction.
|
| DCHECK((output & kRepMask) == 0 ||
|
| base::bits::IsPowerOfTwo32(output & kRepMask));
|
| - GetInfo(node)->set_output_type(output);
|
| + NodeInfo* info = GetInfo(node);
|
| + DCHECK(MachineTypeRepIsSubtype(info->output_type(), output));
|
| + info->set_output_type(output);
|
| }
|
|
|
| bool BothInputsAre(Node* node, Type* type) {
|
| @@ -293,10 +411,6 @@ class RepresentationSelector {
|
| NodeProperties::GetType(node->InputAt(1))->Is(type);
|
| }
|
|
|
| - void EnqueueInputUse(Node* node, int index, UseInfo use) {
|
| - Enqueue(node->InputAt(index), use);
|
| - }
|
| -
|
| void ConvertInput(Node* node, int index, UseInfo use) {
|
| Node* input = node->InputAt(index);
|
| // In the change phase, insert a change before the use if necessary.
|
| @@ -320,7 +434,7 @@ class RepresentationSelector {
|
|
|
| void ProcessInput(Node* node, int index, UseInfo use) {
|
| if (phase_ == PROPAGATE) {
|
| - EnqueueInputUse(node, index, use);
|
| + EnqueueInput(node, index, use);
|
| } else {
|
| ConvertInput(node, index, use);
|
| }
|
| @@ -331,11 +445,11 @@ class RepresentationSelector {
|
| DCHECK_GE(index, NodeProperties::PastContextIndex(node));
|
| for (int i = std::max(index, NodeProperties::FirstEffectIndex(node));
|
| i < NodeProperties::PastEffectIndex(node); ++i) {
|
| - Enqueue(node->InputAt(i)); // Effect inputs: just visit
|
| + EnqueueInput(node, i); // Effect inputs: just visit
|
| }
|
| for (int i = std::max(index, NodeProperties::FirstControlIndex(node));
|
| i < NodeProperties::PastControlIndex(node); ++i) {
|
| - Enqueue(node->InputAt(i)); // Control inputs: just visit
|
| + EnqueueInput(node, i); // Control inputs: just visit
|
| }
|
| }
|
|
|
| @@ -352,10 +466,8 @@ class RepresentationSelector {
|
| }
|
| // Only enqueue other inputs (framestates, effects, control).
|
| for (int i = tagged_count; i < node->InputCount(); i++) {
|
| - Enqueue(node->InputAt(i));
|
| + EnqueueInput(node, i);
|
| }
|
| - // Assume the output is tagged.
|
| - SetOutput(node, kMachAnyTagged);
|
| }
|
|
|
| // Helper for binops of the R x L -> O variety.
|
| @@ -365,7 +477,7 @@ class RepresentationSelector {
|
| ProcessInput(node, 0, left_use);
|
| ProcessInput(node, 1, right_use);
|
| for (int i = 2; i < node->InputCount(); i++) {
|
| - Enqueue(node->InputAt(i));
|
| + EnqueueInput(node, i);
|
| }
|
| SetOutput(node, output);
|
| }
|
| @@ -523,7 +635,7 @@ class RepresentationSelector {
|
| void VisitStateValues(Node* node) {
|
| if (phase_ == PROPAGATE) {
|
| for (int i = 0; i < node->InputCount(); i++) {
|
| - Enqueue(node->InputAt(i), UseInfo::Any());
|
| + EnqueueInput(node, i, UseInfo::Any());
|
| }
|
| } else {
|
| Zone* zone = jsgraph_->zone();
|
| @@ -613,11 +725,11 @@ class RepresentationSelector {
|
|
|
| case IrOpcode::kBranch:
|
| ProcessInput(node, 0, UseInfo::Bool());
|
| - Enqueue(NodeProperties::GetControlInput(node, 0));
|
| + EnqueueInput(node, NodeProperties::FirstControlIndex(node));
|
| break;
|
| case IrOpcode::kSwitch:
|
| ProcessInput(node, 0, UseInfo::TruncatingWord32());
|
| - Enqueue(NodeProperties::GetControlInput(node, 0));
|
| + EnqueueInput(node, NodeProperties::FirstControlIndex(node));
|
| break;
|
| case IrOpcode::kSelect:
|
| return VisitSelect(node, truncation, lowering);
|
| @@ -1104,6 +1216,8 @@ class RepresentationSelector {
|
| break;
|
| default:
|
| VisitInputs(node);
|
| + // Assume the output is tagged.
|
| + SetOutput(node, kMachAnyTagged);
|
| break;
|
| }
|
| }
|
| @@ -1154,6 +1268,10 @@ class RepresentationSelector {
|
| JSGraph* jsgraph_;
|
| size_t const count_; // number of nodes in the graph
|
| ZoneVector<NodeInfo> info_; // node id -> usage information
|
| +#ifdef DEBUG
|
| + ZoneVector<InputUseInfos> node_input_use_infos_; // Debug information about
|
| + // requirements on inputs.
|
| +#endif // DEBUG
|
| NodeVector nodes_; // collected nodes
|
| NodeVector replacements_; // replacements to be done after lowering
|
| Phase phase_; // current phase of algorithm
|
|
|