Commit 99eb5686 authored by bmeurer's avatar bmeurer Committed by Commit bot

[turbofan] Introduce CheckTaggedSigned and CheckTaggedPointer operators.

These are used to check for Smi or HeapObject, and we use them
appropriately in JSNativeContextSpecialization, so we don't need
to introduce dependencies on concrete control flow and/or concrete
frame states.

They will be optimized by a proper check elimination reducer,
which will be added in a separate CL.

R=jarin@chromium.org
BUG=v8:4470

Review-Url: https://codereview.chromium.org/2082523002
Cr-Commit-Position: refs/heads/master@{#37096}
parent 3643f7b1
...@@ -167,6 +167,26 @@ std::ostream& operator<<(std::ostream& os, ...@@ -167,6 +167,26 @@ std::ostream& operator<<(std::ostream& os,
return os << p.value() << "|" << p.rmode() << "|" << p.type(); return os << p.value() << "|" << p.rmode() << "|" << p.type();
} }
size_t hash_value(RegionObservability observability) {
return static_cast<size_t>(observability);
}
std::ostream& operator<<(std::ostream& os, RegionObservability observability) {
switch (observability) {
case RegionObservability::kObservable:
return os << "observable";
case RegionObservability::kNotObservable:
return os << "not-observable";
}
UNREACHABLE();
return os;
}
RegionObservability RegionObservabilityOf(Operator const* op) {
DCHECK_EQ(IrOpcode::kBeginRegion, op->opcode());
return OpParameter<RegionObservability>(op);
}
std::ostream& operator<<(std::ostream& os, std::ostream& operator<<(std::ostream& os,
const ZoneVector<MachineType>* types) { const ZoneVector<MachineType>* types) {
// Print all the MachineTypes, separated by commas. // Print all the MachineTypes, separated by commas.
...@@ -194,8 +214,7 @@ std::ostream& operator<<(std::ostream& os, ...@@ -194,8 +214,7 @@ std::ostream& operator<<(std::ostream& os,
V(OsrNormalEntry, Operator::kFoldable, 0, 1, 1, 0, 1, 1) \ V(OsrNormalEntry, Operator::kFoldable, 0, 1, 1, 0, 1, 1) \
V(OsrLoopEntry, Operator::kFoldable, 0, 1, 1, 0, 1, 1) \ V(OsrLoopEntry, Operator::kFoldable, 0, 1, 1, 0, 1, 1) \
V(Checkpoint, Operator::kKontrol, 0, 1, 1, 0, 1, 0) \ V(Checkpoint, Operator::kKontrol, 0, 1, 1, 0, 1, 0) \
V(BeginRegion, Operator::kNoThrow, 0, 1, 0, 0, 1, 0) \ V(FinishRegion, Operator::kKontrol, 1, 1, 0, 1, 1, 0)
V(FinishRegion, Operator::kNoThrow, 1, 1, 0, 1, 1, 0)
#define CACHED_RETURN_LIST(V) \ #define CACHED_RETURN_LIST(V) \
V(1) \ V(1) \
...@@ -374,6 +393,20 @@ struct CommonOperatorGlobalCache final { ...@@ -374,6 +393,20 @@ struct CommonOperatorGlobalCache final {
CACHED_EFFECT_PHI_LIST(CACHED_EFFECT_PHI) CACHED_EFFECT_PHI_LIST(CACHED_EFFECT_PHI)
#undef CACHED_EFFECT_PHI #undef CACHED_EFFECT_PHI
template <RegionObservability kRegionObservability>
struct BeginRegionOperator final : public Operator1<RegionObservability> {
BeginRegionOperator()
: Operator1<RegionObservability>( // --
IrOpcode::kBeginRegion, Operator::kKontrol, // opcode
"BeginRegion", // name
0, 1, 0, 0, 1, 0, // counts
kRegionObservability) {} // parameter
};
BeginRegionOperator<RegionObservability::kObservable>
kBeginRegionObservableOperator;
BeginRegionOperator<RegionObservability::kNotObservable>
kBeginRegionNotObservableOperator;
template <size_t kInputCount> template <size_t kInputCount>
struct LoopOperator final : public Operator { struct LoopOperator final : public Operator {
LoopOperator() LoopOperator()
...@@ -773,6 +806,17 @@ const Operator* CommonOperatorBuilder::EffectPhi(int effect_input_count) { ...@@ -773,6 +806,17 @@ const Operator* CommonOperatorBuilder::EffectPhi(int effect_input_count) {
0, effect_input_count, 1, 0, 1, 0); // counts 0, effect_input_count, 1, 0, 1, 0); // counts
} }
const Operator* CommonOperatorBuilder::BeginRegion(
RegionObservability region_observability) {
switch (region_observability) {
case RegionObservability::kObservable:
return &cache_.kBeginRegionObservableOperator;
case RegionObservability::kNotObservable:
return &cache_.kBeginRegionNotObservableOperator;
}
UNREACHABLE();
return nullptr;
}
const Operator* CommonOperatorBuilder::StateValues(int arguments) { const Operator* CommonOperatorBuilder::StateValues(int arguments) {
switch (arguments) { switch (arguments) {
......
...@@ -134,8 +134,22 @@ bool operator==(RelocatablePtrConstantInfo const& lhs, ...@@ -134,8 +134,22 @@ bool operator==(RelocatablePtrConstantInfo const& lhs,
RelocatablePtrConstantInfo const& rhs); RelocatablePtrConstantInfo const& rhs);
bool operator!=(RelocatablePtrConstantInfo const& lhs, bool operator!=(RelocatablePtrConstantInfo const& lhs,
RelocatablePtrConstantInfo const& rhs); RelocatablePtrConstantInfo const& rhs);
std::ostream& operator<<(std::ostream&, RelocatablePtrConstantInfo const&); std::ostream& operator<<(std::ostream&, RelocatablePtrConstantInfo const&);
size_t hash_value(RelocatablePtrConstantInfo const& p); size_t hash_value(RelocatablePtrConstantInfo const& p);
// Used to mark a region (as identified by BeginRegion/FinishRegion) as either
// JavaScript-observable or not (i.e. allocations are not JavaScript observable
// themselves, but transitioning stores are).
enum class RegionObservability : uint8_t { kObservable, kNotObservable };
size_t hash_value(RegionObservability);
std::ostream& operator<<(std::ostream&, RegionObservability);
RegionObservability RegionObservabilityOf(Operator const*) WARN_UNUSED_RESULT;
std::ostream& operator<<(std::ostream& os, std::ostream& operator<<(std::ostream& os,
const ZoneVector<MachineType>* types); const ZoneVector<MachineType>* types);
...@@ -189,7 +203,7 @@ class CommonOperatorBuilder final : public ZoneObject { ...@@ -189,7 +203,7 @@ class CommonOperatorBuilder final : public ZoneObject {
int value_input_count); int value_input_count);
const Operator* EffectPhi(int effect_input_count); const Operator* EffectPhi(int effect_input_count);
const Operator* Checkpoint(); const Operator* Checkpoint();
const Operator* BeginRegion(); const Operator* BeginRegion(RegionObservability);
const Operator* FinishRegion(); const Operator* FinishRegion();
const Operator* StateValues(int arguments); const Operator* StateValues(int arguments);
const Operator* ObjectState(int pointer_slots, int id); const Operator* ObjectState(int pointer_slots, int id);
......
...@@ -309,12 +309,26 @@ void EffectControlLinearizer::ProcessNode(Node* node, Node** frame_state, ...@@ -309,12 +309,26 @@ void EffectControlLinearizer::ProcessNode(Node* node, Node** frame_state,
// If the node has a visible effect, then there must be a checkpoint in the // If the node has a visible effect, then there must be a checkpoint in the
// effect chain before we are allowed to place another eager deoptimization // effect chain before we are allowed to place another eager deoptimization
// point. We zap the frame state to ensure this invariant is maintained. // point. We zap the frame state to ensure this invariant is maintained.
if (!node->op()->HasProperty(Operator::kNoWrite)) *frame_state = nullptr; if (region_observability_ == RegionObservability::kObservable &&
!node->op()->HasProperty(Operator::kNoWrite)) {
*frame_state = nullptr;
}
// Remove the end markers of 'atomic' allocation region because the // Remove the end markers of 'atomic' allocation region because the
// region should be wired-in now. // region should be wired-in now.
if (node->opcode() == IrOpcode::kFinishRegion || if (node->opcode() == IrOpcode::kFinishRegion) {
node->opcode() == IrOpcode::kBeginRegion) { // Reset the current region observability.
region_observability_ = RegionObservability::kObservable;
// Update the value uses to the value input of the finish node and
// the effect uses to the effect input.
return RemoveRegionNode(node);
}
if (node->opcode() == IrOpcode::kBeginRegion) {
// Determine the observability for this region and use that for all
// nodes inside the region (i.e. ignore the absence of kNoWrite on
// StoreField and other operators).
DCHECK_NE(RegionObservability::kNotObservable, region_observability_);
region_observability_ = RegionObservabilityOf(node->op());
// Update the value uses to the value input of the finish node and // Update the value uses to the value input of the finish node and
// the effect uses to the effect input. // the effect uses to the effect input.
return RemoveRegionNode(node); return RemoveRegionNode(node);
...@@ -324,6 +338,7 @@ void EffectControlLinearizer::ProcessNode(Node* node, Node** frame_state, ...@@ -324,6 +338,7 @@ void EffectControlLinearizer::ProcessNode(Node* node, Node** frame_state,
if (node->opcode() == IrOpcode::kCheckpoint) { if (node->opcode() == IrOpcode::kCheckpoint) {
// Unlink the check point; effect uses will be updated to the incoming // Unlink the check point; effect uses will be updated to the incoming
// effect that is passed. The frame state is preserved for lowering. // effect that is passed. The frame state is preserved for lowering.
DCHECK_EQ(RegionObservability::kObservable, region_observability_);
*frame_state = NodeProperties::GetFrameStateInput(node, 0); *frame_state = NodeProperties::GetFrameStateInput(node, 0);
node->TrimInputCount(0); node->TrimInputCount(0);
return; return;
...@@ -419,6 +434,12 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node, ...@@ -419,6 +434,12 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node,
case IrOpcode::kCheckBounds: case IrOpcode::kCheckBounds:
state = LowerCheckBounds(node, frame_state, *effect, *control); state = LowerCheckBounds(node, frame_state, *effect, *control);
break; break;
case IrOpcode::kCheckTaggedPointer:
state = LowerCheckTaggedPointer(node, frame_state, *effect, *control);
break;
case IrOpcode::kCheckTaggedSigned:
state = LowerCheckTaggedSigned(node, frame_state, *effect, *control);
break;
case IrOpcode::kCheckedUint32ToInt32: case IrOpcode::kCheckedUint32ToInt32:
state = LowerCheckedUint32ToInt32(node, frame_state, *effect, *control); state = LowerCheckedUint32ToInt32(node, frame_state, *effect, *control);
break; break;
...@@ -783,6 +804,36 @@ EffectControlLinearizer::LowerCheckBounds(Node* node, Node* frame_state, ...@@ -783,6 +804,36 @@ EffectControlLinearizer::LowerCheckBounds(Node* node, Node* frame_state,
return ValueEffectControl(index, effect, control); return ValueEffectControl(index, effect, control);
} }
EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerCheckTaggedPointer(Node* node, Node* frame_state,
Node* effect, Node* control) {
Node* value = node->InputAt(0);
Node* check = ObjectIsSmi(value);
control = effect = graph()->NewNode(common()->DeoptimizeIf(), check,
frame_state, effect, control);
// Make sure the lowered node does not appear in any use lists.
node->TrimInputCount(0);
return ValueEffectControl(value, effect, control);
}
EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerCheckTaggedSigned(Node* node, Node* frame_state,
Node* effect, Node* control) {
Node* value = node->InputAt(0);
Node* check = ObjectIsSmi(value);
control = effect = graph()->NewNode(common()->DeoptimizeUnless(), check,
frame_state, effect, control);
// Make sure the lowered node does not appear in any use lists.
node->TrimInputCount(0);
return ValueEffectControl(value, effect, control);
}
EffectControlLinearizer::ValueEffectControl EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerCheckedUint32ToInt32(Node* node, EffectControlLinearizer::LowerCheckedUint32ToInt32(Node* node,
Node* frame_state, Node* frame_state,
......
...@@ -64,6 +64,10 @@ class EffectControlLinearizer { ...@@ -64,6 +64,10 @@ class EffectControlLinearizer {
Node* control); Node* control);
ValueEffectControl LowerCheckBounds(Node* node, Node* frame_state, ValueEffectControl LowerCheckBounds(Node* node, Node* frame_state,
Node* effect, Node* control); Node* effect, Node* control);
ValueEffectControl LowerCheckTaggedPointer(Node* node, Node* frame_state,
Node* effect, Node* control);
ValueEffectControl LowerCheckTaggedSigned(Node* node, Node* frame_state,
Node* effect, Node* control);
ValueEffectControl LowerCheckedUint32ToInt32(Node* node, Node* frame_state, ValueEffectControl LowerCheckedUint32ToInt32(Node* node, Node* frame_state,
Node* effect, Node* control); Node* effect, Node* control);
ValueEffectControl LowerCheckedFloat64ToInt32(Node* node, Node* frame_state, ValueEffectControl LowerCheckedFloat64ToInt32(Node* node, Node* frame_state,
...@@ -138,6 +142,7 @@ class EffectControlLinearizer { ...@@ -138,6 +142,7 @@ class EffectControlLinearizer {
JSGraph* js_graph_; JSGraph* js_graph_;
Schedule* schedule_; Schedule* schedule_;
Zone* temp_zone_; Zone* temp_zone_;
RegionObservability region_observability_ = RegionObservability::kObservable;
SetOncePointer<Operator const> to_number_operator_; SetOncePointer<Operator const> to_number_operator_;
}; };
......
...@@ -37,7 +37,8 @@ class AllocationBuilder final { ...@@ -37,7 +37,8 @@ class AllocationBuilder final {
// Primitive allocation of static size. // Primitive allocation of static size.
void Allocate(int size, PretenureFlag pretenure = NOT_TENURED) { void Allocate(int size, PretenureFlag pretenure = NOT_TENURED) {
effect_ = graph()->NewNode(common()->BeginRegion(), effect_); effect_ = graph()->NewNode(
common()->BeginRegion(RegionObservability::kNotObservable), effect_);
allocation_ = allocation_ =
graph()->NewNode(simplified()->Allocate(pretenure), graph()->NewNode(simplified()->Allocate(pretenure),
jsgraph()->Constant(size), effect_, control_); jsgraph()->Constant(size), effect_, control_);
...@@ -948,7 +949,8 @@ Node* JSCreateLowering::AllocateFastLiteral( ...@@ -948,7 +949,8 @@ Node* JSCreateLowering::AllocateFastLiteral(
site_context->ExitScope(current_site, boilerplate_object); site_context->ExitScope(current_site, boilerplate_object);
} else if (property_details.representation().IsDouble()) { } else if (property_details.representation().IsDouble()) {
// Allocate a mutable HeapNumber box and store the value into it. // Allocate a mutable HeapNumber box and store the value into it.
effect = graph()->NewNode(common()->BeginRegion(), effect); effect = graph()->NewNode(
common()->BeginRegion(RegionObservability::kNotObservable), effect);
value = effect = graph()->NewNode( value = effect = graph()->NewNode(
simplified()->Allocate(NOT_TENURED), simplified()->Allocate(NOT_TENURED),
jsgraph()->Constant(HeapNumber::kSize), effect, control); jsgraph()->Constant(HeapNumber::kSize), effect, control);
......
...@@ -125,17 +125,17 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess( ...@@ -125,17 +125,17 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
} }
// Ensure that {receiver} is a heap object. // Ensure that {receiver} is a heap object.
Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver);
Node* receiverissmi_control = nullptr; Node* receiverissmi_control = nullptr;
Node* receiverissmi_effect = effect; Node* receiverissmi_effect = effect;
if (receiverissmi_possible) { if (receiverissmi_possible) {
Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver);
Node* branch = graph()->NewNode(common()->Branch(), check, control); Node* branch = graph()->NewNode(common()->Branch(), check, control);
control = graph()->NewNode(common()->IfFalse(), branch); control = graph()->NewNode(common()->IfFalse(), branch);
receiverissmi_control = graph()->NewNode(common()->IfTrue(), branch); receiverissmi_control = graph()->NewNode(common()->IfTrue(), branch);
receiverissmi_effect = effect; receiverissmi_effect = effect;
} else { } else {
control = effect = graph()->NewNode(common()->DeoptimizeIf(), check, receiver = effect = graph()->NewNode(simplified()->CheckTaggedPointer(),
frame_state, effect, control); receiver, effect, control);
} }
// Load the {receiver} map. The resulting effect is the dominating effect for // Load the {receiver} map. The resulting effect is the dominating effect for
...@@ -288,8 +288,9 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess( ...@@ -288,8 +288,9 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
!FLAG_unbox_double_fields) { !FLAG_unbox_double_fields) {
if (access_info.HasTransitionMap()) { if (access_info.HasTransitionMap()) {
// Allocate a MutableHeapNumber for the new property. // Allocate a MutableHeapNumber for the new property.
this_effect = this_effect = graph()->NewNode(
graph()->NewNode(common()->BeginRegion(), this_effect); common()->BeginRegion(RegionObservability::kNotObservable),
this_effect);
Node* this_box = this_effect = Node* this_box = this_effect =
graph()->NewNode(simplified()->Allocate(NOT_TENURED), graph()->NewNode(simplified()->Allocate(NOT_TENURED),
jsgraph()->Constant(HeapNumber::kSize), jsgraph()->Constant(HeapNumber::kSize),
...@@ -319,19 +320,12 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess( ...@@ -319,19 +320,12 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
field_access.machine_type = MachineType::Float64(); field_access.machine_type = MachineType::Float64();
} }
} else if (field_type->Is(Type::TaggedSigned())) { } else if (field_type->Is(Type::TaggedSigned())) {
Node* check = this_value = this_effect =
graph()->NewNode(simplified()->ObjectIsSmi(), this_value); graph()->NewNode(simplified()->CheckTaggedSigned(), this_value,
this_control = this_effect =
graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state,
this_effect, this_control); this_effect, this_control);
this_value =
graph()->NewNode(simplified()->TypeGuard(type_cache_.kSmi),
this_value, this_control);
} else if (field_type->Is(Type::TaggedPointer())) { } else if (field_type->Is(Type::TaggedPointer())) {
Node* check = this_value = this_effect =
graph()->NewNode(simplified()->ObjectIsSmi(), this_value); graph()->NewNode(simplified()->CheckTaggedPointer(), this_value,
this_control = this_effect =
graph()->NewNode(common()->DeoptimizeIf(), check, frame_state,
this_effect, this_control); this_effect, this_control);
if (field_type->NumClasses() == 1) { if (field_type->NumClasses() == 1) {
// Emit a map check for the value. // Emit a map check for the value.
...@@ -352,7 +346,9 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess( ...@@ -352,7 +346,9 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
} }
Handle<Map> transition_map; Handle<Map> transition_map;
if (access_info.transition_map().ToHandle(&transition_map)) { if (access_info.transition_map().ToHandle(&transition_map)) {
this_effect = graph()->NewNode(common()->BeginRegion(), this_effect); this_effect = graph()->NewNode(
common()->BeginRegion(RegionObservability::kObservable),
this_effect);
this_effect = graph()->NewNode( this_effect = graph()->NewNode(
simplified()->StoreField(AccessBuilder::ForMap()), this_receiver, simplified()->StoreField(AccessBuilder::ForMap()), this_receiver,
jsgraph()->Constant(transition_map), this_effect, this_control); jsgraph()->Constant(transition_map), this_effect, this_control);
...@@ -531,9 +527,8 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess( ...@@ -531,9 +527,8 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
ZoneVector<Node*> controls(zone()); ZoneVector<Node*> controls(zone());
// Ensure that {receiver} is a heap object. // Ensure that {receiver} is a heap object.
Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver); receiver = effect = graph()->NewNode(simplified()->CheckTaggedPointer(),
control = effect = graph()->NewNode(common()->DeoptimizeIf(), check, receiver, effect, control);
frame_state, effect, control);
// Load the {receiver} map. The resulting effect is the dominating effect for // Load the {receiver} map. The resulting effect is the dominating effect for
// all (polymorphic) branches. // all (polymorphic) branches.
...@@ -785,12 +780,9 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess( ...@@ -785,12 +780,9 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
} else { } else {
DCHECK_EQ(AccessMode::kStore, access_mode); DCHECK_EQ(AccessMode::kStore, access_mode);
if (IsFastSmiElementsKind(elements_kind)) { if (IsFastSmiElementsKind(elements_kind)) {
Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), this_value); this_value = this_effect =
this_control = this_effect = graph()->NewNode(simplified()->CheckTaggedSigned(), this_value,
graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state,
this_effect, this_control); this_effect, this_control);
this_value = graph()->NewNode(simplified()->TypeGuard(type_cache_.kSmi),
this_value, this_control);
} else if (IsFastDoubleElementsKind(elements_kind)) { } else if (IsFastDoubleElementsKind(elements_kind)) {
Node* check = Node* check =
graph()->NewNode(simplified()->ObjectIsNumber(), this_value); graph()->NewNode(simplified()->ObjectIsNumber(), this_value);
......
...@@ -442,33 +442,36 @@ struct MachineOperatorGlobalCache { ...@@ -442,33 +442,36 @@ struct MachineOperatorGlobalCache {
PURE_OPTIONAL_OP_LIST(PURE) PURE_OPTIONAL_OP_LIST(PURE)
#undef PURE #undef PURE
#define LOAD(Type) \ #define LOAD(Type) \
struct Load##Type##Operator final : public Operator1<LoadRepresentation> { \ struct Load##Type##Operator final : public Operator1<LoadRepresentation> { \
Load##Type##Operator() \ Load##Type##Operator() \
: Operator1<LoadRepresentation>( \ : Operator1<LoadRepresentation>( \
IrOpcode::kLoad, Operator::kNoThrow | Operator::kNoWrite, \ IrOpcode::kLoad, \
"Load", 2, 1, 1, 1, 1, 0, MachineType::Type()) {} \ Operator::kNoDeopt | Operator::kNoThrow | Operator::kNoWrite, \
}; \ "Load", 2, 1, 1, 1, 1, 0, MachineType::Type()) {} \
struct CheckedLoad##Type##Operator final \ }; \
: public Operator1<CheckedLoadRepresentation> { \ struct CheckedLoad##Type##Operator final \
CheckedLoad##Type##Operator() \ : public Operator1<CheckedLoadRepresentation> { \
: Operator1<CheckedLoadRepresentation>( \ CheckedLoad##Type##Operator() \
IrOpcode::kCheckedLoad, Operator::kNoThrow | Operator::kNoWrite, \ : Operator1<CheckedLoadRepresentation>( \
"CheckedLoad", 3, 1, 1, 1, 1, 0, MachineType::Type()) {} \ IrOpcode::kCheckedLoad, \
}; \ Operator::kNoDeopt | Operator::kNoThrow | Operator::kNoWrite, \
Load##Type##Operator kLoad##Type; \ "CheckedLoad", 3, 1, 1, 1, 1, 0, MachineType::Type()) {} \
}; \
Load##Type##Operator kLoad##Type; \
CheckedLoad##Type##Operator kCheckedLoad##Type; CheckedLoad##Type##Operator kCheckedLoad##Type;
MACHINE_TYPE_LIST(LOAD) MACHINE_TYPE_LIST(LOAD)
#undef LOAD #undef LOAD
#define STACKSLOT(Type) \ #define STACKSLOT(Type) \
struct StackSlot##Type##Operator final \ struct StackSlot##Type##Operator final \
: public Operator1<MachineRepresentation> { \ : public Operator1<MachineRepresentation> { \
StackSlot##Type##Operator() \ StackSlot##Type##Operator() \
: Operator1<MachineRepresentation>( \ : Operator1<MachineRepresentation>( \
IrOpcode::kStackSlot, Operator::kNoThrow, "StackSlot", 0, 0, 0, \ IrOpcode::kStackSlot, Operator::kNoDeopt | Operator::kNoThrow, \
1, 0, 0, MachineType::Type().representation()) {} \ "StackSlot", 0, 0, 0, 1, 0, 0, \
}; \ MachineType::Type().representation()) {} \
}; \
StackSlot##Type##Operator kStackSlot##Type; StackSlot##Type##Operator kStackSlot##Type;
MACHINE_TYPE_LIST(STACKSLOT) MACHINE_TYPE_LIST(STACKSLOT)
#undef STACKSLOT #undef STACKSLOT
...@@ -477,7 +480,8 @@ struct MachineOperatorGlobalCache { ...@@ -477,7 +480,8 @@ struct MachineOperatorGlobalCache {
struct Store##Type##Operator : public Operator1<StoreRepresentation> { \ struct Store##Type##Operator : public Operator1<StoreRepresentation> { \
explicit Store##Type##Operator(WriteBarrierKind write_barrier_kind) \ explicit Store##Type##Operator(WriteBarrierKind write_barrier_kind) \
: Operator1<StoreRepresentation>( \ : Operator1<StoreRepresentation>( \
IrOpcode::kStore, Operator::kNoRead | Operator::kNoThrow, \ IrOpcode::kStore, \
Operator::kNoDeopt | Operator::kNoRead | Operator::kNoThrow, \
"Store", 3, 1, 1, 0, 1, 0, \ "Store", 3, 1, 1, 0, 1, 0, \
StoreRepresentation(MachineRepresentation::Type, \ StoreRepresentation(MachineRepresentation::Type, \
write_barrier_kind)) {} \ write_barrier_kind)) {} \
...@@ -506,7 +510,8 @@ struct MachineOperatorGlobalCache { ...@@ -506,7 +510,8 @@ struct MachineOperatorGlobalCache {
: public Operator1<CheckedStoreRepresentation> { \ : public Operator1<CheckedStoreRepresentation> { \
CheckedStore##Type##Operator() \ CheckedStore##Type##Operator() \
: Operator1<CheckedStoreRepresentation>( \ : Operator1<CheckedStoreRepresentation>( \
IrOpcode::kCheckedStore, Operator::kNoRead | Operator::kNoThrow, \ IrOpcode::kCheckedStore, \
Operator::kNoDeopt | Operator::kNoRead | Operator::kNoThrow, \
"CheckedStore", 4, 1, 1, 0, 1, 0, MachineRepresentation::Type) { \ "CheckedStore", 4, 1, 1, 0, 1, 0, MachineRepresentation::Type) { \
} \ } \
}; \ }; \
...@@ -519,14 +524,15 @@ struct MachineOperatorGlobalCache { ...@@ -519,14 +524,15 @@ struct MachineOperatorGlobalCache {
MACHINE_REPRESENTATION_LIST(STORE) MACHINE_REPRESENTATION_LIST(STORE)
#undef STORE #undef STORE
#define ATOMIC_LOAD(Type) \ #define ATOMIC_LOAD(Type) \
struct AtomicLoad##Type##Operator final \ struct AtomicLoad##Type##Operator final \
: public Operator1<LoadRepresentation> { \ : public Operator1<LoadRepresentation> { \
AtomicLoad##Type##Operator() \ AtomicLoad##Type##Operator() \
: Operator1<LoadRepresentation>( \ : Operator1<LoadRepresentation>( \
IrOpcode::kAtomicLoad, Operator::kNoThrow | Operator::kNoWrite, \ IrOpcode::kAtomicLoad, \
"AtomicLoad", 2, 1, 1, 1, 1, 0, MachineType::Type()) {} \ Operator::kNoDeopt | Operator::kNoThrow | Operator::kNoWrite, \
}; \ "AtomicLoad", 2, 1, 1, 1, 1, 0, MachineType::Type()) {} \
}; \
AtomicLoad##Type##Operator kAtomicLoad##Type; AtomicLoad##Type##Operator kAtomicLoad##Type;
ATOMIC_TYPE_LIST(ATOMIC_LOAD) ATOMIC_TYPE_LIST(ATOMIC_LOAD)
#undef ATOMIC_LOAD #undef ATOMIC_LOAD
...@@ -536,7 +542,8 @@ struct MachineOperatorGlobalCache { ...@@ -536,7 +542,8 @@ struct MachineOperatorGlobalCache {
: public Operator1<MachineRepresentation> { \ : public Operator1<MachineRepresentation> { \
AtomicStore##Type##Operator() \ AtomicStore##Type##Operator() \
: Operator1<MachineRepresentation>( \ : Operator1<MachineRepresentation>( \
IrOpcode::kAtomicStore, Operator::kNoRead | Operator::kNoThrow, \ IrOpcode::kAtomicStore, \
Operator::kNoDeopt | Operator::kNoRead | Operator::kNoThrow, \
"AtomicStore", 3, 1, 1, 0, 1, 0, MachineRepresentation::Type) {} \ "AtomicStore", 3, 1, 1, 0, 1, 0, MachineRepresentation::Type) {} \
}; \ }; \
AtomicStore##Type##Operator kAtomicStore##Type; AtomicStore##Type##Operator kAtomicStore##Type;
......
...@@ -236,6 +236,8 @@ ...@@ -236,6 +236,8 @@
V(ChangeTaggedToBit) \ V(ChangeTaggedToBit) \
V(ChangeBitToTagged) \ V(ChangeBitToTagged) \
V(CheckBounds) \ V(CheckBounds) \
V(CheckTaggedPointer) \
V(CheckTaggedSigned) \
V(CheckedUint32ToInt32) \ V(CheckedUint32ToInt32) \
V(CheckedFloat64ToInt32) \ V(CheckedFloat64ToInt32) \
V(CheckedTaggedToInt32) \ V(CheckedTaggedToInt32) \
......
...@@ -36,18 +36,18 @@ class Operator : public ZoneObject { ...@@ -36,18 +36,18 @@ class Operator : public ZoneObject {
// transformations for nodes that have this operator. // transformations for nodes that have this operator.
enum Property { enum Property {
kNoProperties = 0, kNoProperties = 0,
kReducible = 1 << 0, // Participates in strength reduction. kCommutative = 1 << 0, // OP(a, b) == OP(b, a) for all inputs.
kCommutative = 1 << 1, // OP(a, b) == OP(b, a) for all inputs. kAssociative = 1 << 1, // OP(a, OP(b,c)) == OP(OP(a,b), c) for all inputs.
kAssociative = 1 << 2, // OP(a, OP(b,c)) == OP(OP(a,b), c) for all inputs. kIdempotent = 1 << 2, // OP(a); OP(a) == OP(a).
kIdempotent = 1 << 3, // OP(a); OP(a) == OP(a). kNoRead = 1 << 3, // Has no scheduling dependency on Effects
kNoRead = 1 << 4, // Has no scheduling dependency on Effects kNoWrite = 1 << 4, // Does not modify any Effects and thereby
kNoWrite = 1 << 5, // Does not modify any Effects and thereby
// create new scheduling dependencies. // create new scheduling dependencies.
kNoThrow = 1 << 6, // Can never generate an exception. kNoThrow = 1 << 5, // Can never generate an exception.
kNoDeopt = 1 << 6, // Can never generate an eager deoptimization exit.
kFoldable = kNoRead | kNoWrite, kFoldable = kNoRead | kNoWrite,
kKontrol = kFoldable | kNoThrow, kKontrol = kNoDeopt | kFoldable | kNoThrow,
kEliminatable = kNoWrite | kNoThrow, kEliminatable = kNoDeopt | kNoWrite | kNoThrow,
kPure = kNoRead | kNoWrite | kNoThrow | kIdempotent kPure = kNoDeopt | kNoRead | kNoWrite | kNoThrow | kIdempotent
}; };
typedef base::Flags<Property, uint8_t> Properties; typedef base::Flags<Property, uint8_t> Properties;
......
...@@ -672,7 +672,7 @@ class RepresentationSelector { ...@@ -672,7 +672,7 @@ class RepresentationSelector {
Type* GetUpperBound(Node* node) { return NodeProperties::GetType(node); } Type* GetUpperBound(Node* node) { return NodeProperties::GetType(node); }
bool InputIs(Node* node, Type* type) { bool InputIs(Node* node, Type* type) {
DCHECK_EQ(1, node->InputCount()); DCHECK_EQ(1, node->op()->ValueInputCount());
return GetUpperBound(node->InputAt(0))->Is(type); return GetUpperBound(node->InputAt(0))->Is(type);
} }
...@@ -772,8 +772,9 @@ class RepresentationSelector { ...@@ -772,8 +772,9 @@ class RepresentationSelector {
// Helper for unops of the I -> O variety. // Helper for unops of the I -> O variety.
void VisitUnop(Node* node, UseInfo input_use, MachineRepresentation output) { void VisitUnop(Node* node, UseInfo input_use, MachineRepresentation output) {
DCHECK_EQ(1, node->InputCount()); DCHECK_EQ(1, node->op()->ValueInputCount());
ProcessInput(node, 0, input_use); ProcessInput(node, 0, input_use);
ProcessRemainingInputs(node, 1);
SetOutput(node, output); SetOutput(node, output);
} }
...@@ -1669,6 +1670,31 @@ class RepresentationSelector { ...@@ -1669,6 +1670,31 @@ class RepresentationSelector {
UseInfo::TruncatingWord32(), MachineRepresentation::kWord32); UseInfo::TruncatingWord32(), MachineRepresentation::kWord32);
return; return;
} }
case IrOpcode::kCheckTaggedPointer: {
VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kTagged);
if (lower()) {
if (InputIs(node, Type::TaggedPointer())) {
DeferReplacement(node, node->InputAt(0));
}
}
return;
}
case IrOpcode::kCheckTaggedSigned: {
if (SmiValuesAre32Bits() && truncation.TruncatesToWord32()) {
// TODO(jarin,bmeurer): Add CheckedSignedSmallAsWord32?
VisitUnop(node, UseInfo::CheckedSigned32AsWord32(),
MachineRepresentation::kWord32);
DeferReplacement(node, node->InputAt(0));
} else {
VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kTagged);
if (lower()) {
if (InputIs(node, Type::TaggedSigned())) {
DeferReplacement(node, node->InputAt(0));
}
}
}
return;
}
case IrOpcode::kAllocate: { case IrOpcode::kAllocate: {
ProcessInput(node, 0, UseInfo::TruncatingWord32()); ProcessInput(node, 0, UseInfo::TruncatingWord32());
......
...@@ -309,6 +309,8 @@ CompareOperationHints::Hint CompareOperationHintOf(const Operator* op) { ...@@ -309,6 +309,8 @@ CompareOperationHints::Hint CompareOperationHintOf(const Operator* op) {
V(SpeculativeNumberModulus) V(SpeculativeNumberModulus)
#define CHECKED_OP_LIST(V) \ #define CHECKED_OP_LIST(V) \
V(CheckTaggedPointer) \
V(CheckTaggedSigned) \
V(CheckedUint32ToInt32) \ V(CheckedUint32ToInt32) \
V(CheckedFloat64ToInt32) \ V(CheckedFloat64ToInt32) \
V(CheckedTaggedToInt32) \ V(CheckedTaggedToInt32) \
...@@ -328,8 +330,9 @@ struct SimplifiedOperatorGlobalCache final { ...@@ -328,8 +330,9 @@ struct SimplifiedOperatorGlobalCache final {
#define CHECKED(Name) \ #define CHECKED(Name) \
struct Name##Operator final : public Operator { \ struct Name##Operator final : public Operator { \
Name##Operator() \ Name##Operator() \
: Operator(IrOpcode::k##Name, Operator::kPure, #Name, 1, 1, 1, 1, 1, \ : Operator(IrOpcode::k##Name, \
0) {} \ Operator::kFoldable | Operator::kNoThrow, #Name, 1, 1, 1, \
1, 1, 0) {} \
}; \ }; \
Name##Operator k##Name; Name##Operator k##Name;
CHECKED_OP_LIST(CHECKED) CHECKED_OP_LIST(CHECKED)
...@@ -339,9 +342,10 @@ struct SimplifiedOperatorGlobalCache final { ...@@ -339,9 +342,10 @@ struct SimplifiedOperatorGlobalCache final {
struct CheckFloat64HoleNaNOperatortor final struct CheckFloat64HoleNaNOperatortor final
: public Operator1<CheckFloat64HoleMode> { : public Operator1<CheckFloat64HoleMode> {
CheckFloat64HoleNaNOperatortor() CheckFloat64HoleNaNOperatortor()
: Operator1<CheckFloat64HoleMode>(IrOpcode::kCheckFloat64Hole, : Operator1<CheckFloat64HoleMode>(
Operator::kPure, "CheckFloat64Hole", IrOpcode::kCheckFloat64Hole,
1, 1, 1, 1, 1, 0, kMode) {} Operator::kFoldable | Operator::kNoDeopt, "CheckFloat64Hole", 1,
1, 1, 1, 1, 0, kMode) {}
}; };
CheckFloat64HoleNaNOperatortor<CheckFloat64HoleMode::kAllowReturnHole> CheckFloat64HoleNaNOperatortor<CheckFloat64HoleMode::kAllowReturnHole>
kCheckFloat64HoleAllowReturnHoleOperator; kCheckFloat64HoleAllowReturnHoleOperator;
...@@ -351,9 +355,10 @@ struct SimplifiedOperatorGlobalCache final { ...@@ -351,9 +355,10 @@ struct SimplifiedOperatorGlobalCache final {
template <CheckTaggedHoleMode kMode> template <CheckTaggedHoleMode kMode>
struct CheckTaggedHoleOperator final : public Operator1<CheckTaggedHoleMode> { struct CheckTaggedHoleOperator final : public Operator1<CheckTaggedHoleMode> {
CheckTaggedHoleOperator() CheckTaggedHoleOperator()
: Operator1<CheckTaggedHoleMode>(IrOpcode::kCheckTaggedHole, : Operator1<CheckTaggedHoleMode>(
Operator::kPure, "CheckTaggedHole", 1, IrOpcode::kCheckTaggedHole,
1, 1, 1, 1, 0, kMode) {} Operator::kFoldable | Operator::kNoDeopt, "CheckTaggedHole", 1, 1,
1, 1, 1, 0, kMode) {}
}; };
CheckTaggedHoleOperator<CheckTaggedHoleMode::kConvertHoleToUndefined> CheckTaggedHoleOperator<CheckTaggedHoleMode::kConvertHoleToUndefined>
kCheckTaggedHoleConvertHoleToUndefinedOperator; kCheckTaggedHoleConvertHoleToUndefinedOperator;
...@@ -362,16 +367,18 @@ struct SimplifiedOperatorGlobalCache final { ...@@ -362,16 +367,18 @@ struct SimplifiedOperatorGlobalCache final {
struct CheckIfOperator final : public Operator { struct CheckIfOperator final : public Operator {
CheckIfOperator() CheckIfOperator()
: Operator(IrOpcode::kCheckIf, Operator::kPure, "CheckIf", 1, 1, 1, 0, : Operator(IrOpcode::kCheckIf, Operator::kFoldable | Operator::kNoDeopt,
1, 0) {} "CheckIf", 1, 1, 1, 0, 1, 0) {}
}; };
CheckIfOperator kCheckIf; CheckIfOperator kCheckIf;
template <PretenureFlag kPretenure> template <PretenureFlag kPretenure>
struct AllocateOperator final : public Operator1<PretenureFlag> { struct AllocateOperator final : public Operator1<PretenureFlag> {
AllocateOperator() AllocateOperator()
: Operator1<PretenureFlag>(IrOpcode::kAllocate, Operator::kNoThrow, : Operator1<PretenureFlag>(
"Allocate", 1, 1, 1, 1, 1, 0, kPretenure) {} IrOpcode::kAllocate,
Operator::kNoDeopt | Operator::kNoThrow | Operator::kNoWrite,
"Allocate", 1, 1, 1, 1, 1, 0, kPretenure) {}
}; };
AllocateOperator<NOT_TENURED> kAllocateNotTenuredOperator; AllocateOperator<NOT_TENURED> kAllocateNotTenuredOperator;
AllocateOperator<TENURED> kAllocateTenuredOperator; AllocateOperator<TENURED> kAllocateTenuredOperator;
...@@ -379,17 +386,19 @@ struct SimplifiedOperatorGlobalCache final { ...@@ -379,17 +386,19 @@ struct SimplifiedOperatorGlobalCache final {
#define BUFFER_ACCESS(Type, type, TYPE, ctype, size) \ #define BUFFER_ACCESS(Type, type, TYPE, ctype, size) \
struct LoadBuffer##Type##Operator final : public Operator1<BufferAccess> { \ struct LoadBuffer##Type##Operator final : public Operator1<BufferAccess> { \
LoadBuffer##Type##Operator() \ LoadBuffer##Type##Operator() \
: Operator1<BufferAccess>(IrOpcode::kLoadBuffer, \ : Operator1<BufferAccess>( \
Operator::kNoThrow | Operator::kNoWrite, \ IrOpcode::kLoadBuffer, \
"LoadBuffer", 3, 1, 1, 1, 1, 0, \ Operator::kNoDeopt | Operator::kNoThrow | Operator::kNoWrite, \
BufferAccess(kExternal##Type##Array)) {} \ "LoadBuffer", 3, 1, 1, 1, 1, 0, \
BufferAccess(kExternal##Type##Array)) {} \
}; \ }; \
struct StoreBuffer##Type##Operator final : public Operator1<BufferAccess> { \ struct StoreBuffer##Type##Operator final : public Operator1<BufferAccess> { \
StoreBuffer##Type##Operator() \ StoreBuffer##Type##Operator() \
: Operator1<BufferAccess>(IrOpcode::kStoreBuffer, \ : Operator1<BufferAccess>( \
Operator::kNoRead | Operator::kNoThrow, \ IrOpcode::kStoreBuffer, \
"StoreBuffer", 4, 1, 1, 0, 1, 0, \ Operator::kNoDeopt | Operator::kNoRead | Operator::kNoThrow, \
BufferAccess(kExternal##Type##Array)) {} \ "StoreBuffer", 4, 1, 1, 0, 1, 0, \
BufferAccess(kExternal##Type##Array)) {} \
}; \ }; \
LoadBuffer##Type##Operator kLoadBuffer##Type; \ LoadBuffer##Type##Operator kLoadBuffer##Type; \
StoreBuffer##Type##Operator kStoreBuffer##Type; StoreBuffer##Type##Operator kStoreBuffer##Type;
...@@ -451,8 +460,9 @@ const Operator* SimplifiedOperatorBuilder::ReferenceEqual(Type* type) { ...@@ -451,8 +460,9 @@ const Operator* SimplifiedOperatorBuilder::ReferenceEqual(Type* type) {
const Operator* SimplifiedOperatorBuilder::CheckBounds() { const Operator* SimplifiedOperatorBuilder::CheckBounds() {
// TODO(bmeurer): Cache this operator. Make it pure! // TODO(bmeurer): Cache this operator. Make it pure!
return new (zone()) Operator(IrOpcode::kCheckBounds, Operator::kPure, return new (zone())
"CheckBounds", 2, 1, 1, 1, 1, 0); Operator(IrOpcode::kCheckBounds, Operator::kFoldable | Operator::kNoThrow,
"CheckBounds", 2, 1, 1, 1, 1, 0);
} }
const Operator* SimplifiedOperatorBuilder::TypeGuard(Type* type) { const Operator* SimplifiedOperatorBuilder::TypeGuard(Type* type) {
...@@ -509,11 +519,12 @@ const Operator* SimplifiedOperatorBuilder::StoreBuffer(BufferAccess access) { ...@@ -509,11 +519,12 @@ const Operator* SimplifiedOperatorBuilder::StoreBuffer(BufferAccess access) {
return nullptr; return nullptr;
} }
#define SPECULATIVE_BINOP_DEF(Name) \ #define SPECULATIVE_BINOP_DEF(Name) \
const Operator* SimplifiedOperatorBuilder::Name( \ const Operator* SimplifiedOperatorBuilder::Name( \
BinaryOperationHints::Hint hint) { \ BinaryOperationHints::Hint hint) { \
return new (zone()) Operator1<BinaryOperationHints::Hint>( \ return new (zone()) Operator1<BinaryOperationHints::Hint>( \
IrOpcode::k##Name, Operator::kPure, #Name, 2, 1, 1, 1, 1, 1, hint); \ IrOpcode::k##Name, Operator::kFoldable | Operator::kNoThrow, #Name, 2, \
1, 1, 1, 1, 1, hint); \
} }
SPECULATIVE_BINOP_LIST(SPECULATIVE_BINOP_DEF) SPECULATIVE_BINOP_LIST(SPECULATIVE_BINOP_DEF)
#undef SPECULATIVE_BINOP_DEF #undef SPECULATIVE_BINOP_DEF
...@@ -521,21 +532,24 @@ SPECULATIVE_BINOP_LIST(SPECULATIVE_BINOP_DEF) ...@@ -521,21 +532,24 @@ SPECULATIVE_BINOP_LIST(SPECULATIVE_BINOP_DEF)
const Operator* SimplifiedOperatorBuilder::SpeculativeNumberEqual( const Operator* SimplifiedOperatorBuilder::SpeculativeNumberEqual(
CompareOperationHints::Hint hint) { CompareOperationHints::Hint hint) {
return new (zone()) Operator1<CompareOperationHints::Hint>( return new (zone()) Operator1<CompareOperationHints::Hint>(
IrOpcode::kSpeculativeNumberEqual, Operator::kPure, IrOpcode::kSpeculativeNumberEqual,
"SpeculativeNumberEqual", 2, 1, 1, 1, 1, 1, hint); Operator::kFoldable | Operator::kNoThrow, "SpeculativeNumberEqual", 2, 1,
1, 1, 1, 1, hint);
} }
const Operator* SimplifiedOperatorBuilder::SpeculativeNumberLessThan( const Operator* SimplifiedOperatorBuilder::SpeculativeNumberLessThan(
CompareOperationHints::Hint hint) { CompareOperationHints::Hint hint) {
return new (zone()) Operator1<CompareOperationHints::Hint>( return new (zone()) Operator1<CompareOperationHints::Hint>(
IrOpcode::kSpeculativeNumberLessThan, Operator::kPure, IrOpcode::kSpeculativeNumberLessThan,
"SpeculativeNumberLessThan", 2, 1, 1, 1, 1, 1, hint); Operator::kFoldable | Operator::kNoThrow, "SpeculativeNumberLessThan", 2,
1, 1, 1, 1, 1, hint);
} }
const Operator* SimplifiedOperatorBuilder::SpeculativeNumberLessThanOrEqual( const Operator* SimplifiedOperatorBuilder::SpeculativeNumberLessThanOrEqual(
CompareOperationHints::Hint hint) { CompareOperationHints::Hint hint) {
return new (zone()) Operator1<CompareOperationHints::Hint>( return new (zone()) Operator1<CompareOperationHints::Hint>(
IrOpcode::kSpeculativeNumberLessThanOrEqual, Operator::kPure, IrOpcode::kSpeculativeNumberLessThanOrEqual,
Operator::kFoldable | Operator::kNoThrow,
"SpeculativeNumberLessThanOrEqual", 2, 1, 1, 1, 1, 1, hint); "SpeculativeNumberLessThanOrEqual", 2, 1, 1, 1, 1, 1, hint);
} }
...@@ -545,12 +559,12 @@ const Operator* SimplifiedOperatorBuilder::SpeculativeNumberLessThanOrEqual( ...@@ -545,12 +559,12 @@ const Operator* SimplifiedOperatorBuilder::SpeculativeNumberLessThanOrEqual(
V(LoadElement, ElementAccess, Operator::kNoWrite, 2, 1, 1) \ V(LoadElement, ElementAccess, Operator::kNoWrite, 2, 1, 1) \
V(StoreElement, ElementAccess, Operator::kNoRead, 3, 1, 0) V(StoreElement, ElementAccess, Operator::kNoRead, 3, 1, 0)
#define ACCESS(Name, Type, properties, value_input_count, control_input_count, \ #define ACCESS(Name, Type, properties, value_input_count, control_input_count, \
output_count) \ output_count) \
const Operator* SimplifiedOperatorBuilder::Name(const Type& access) { \ const Operator* SimplifiedOperatorBuilder::Name(const Type& access) { \
return new (zone()) \ return new (zone()) \
Operator1<Type>(IrOpcode::k##Name, Operator::kNoThrow | properties, \ Operator1<Type>(IrOpcode::k##Name, \
Operator::kNoDeopt | Operator::kNoThrow | properties, \
#Name, value_input_count, 1, control_input_count, \ #Name, value_input_count, 1, control_input_count, \
output_count, 1, 0, access); \ output_count, 1, 0, access); \
} }
......
...@@ -237,6 +237,8 @@ class SimplifiedOperatorBuilder final : public ZoneObject { ...@@ -237,6 +237,8 @@ class SimplifiedOperatorBuilder final : public ZoneObject {
const Operator* TruncateTaggedToFloat64(); const Operator* TruncateTaggedToFloat64();
const Operator* CheckBounds(); const Operator* CheckBounds();
const Operator* CheckTaggedPointer();
const Operator* CheckTaggedSigned();
const Operator* CheckedUint32ToInt32(); const Operator* CheckedUint32ToInt32();
const Operator* CheckedFloat64ToInt32(); const Operator* CheckedFloat64ToInt32();
......
...@@ -2008,6 +2008,16 @@ Type* Typer::Visitor::TypeCheckBounds(Node* node) { ...@@ -2008,6 +2008,16 @@ Type* Typer::Visitor::TypeCheckBounds(Node* node) {
return Type::Unsigned31(); return Type::Unsigned31();
} }
Type* Typer::Visitor::TypeCheckTaggedPointer(Node* node) {
Type* arg = Operand(node, 0);
return Type::Intersect(arg, Type::TaggedPointer(), zone());
}
Type* Typer::Visitor::TypeCheckTaggedSigned(Node* node) {
Type* arg = Operand(node, 0);
return Type::Intersect(arg, typer_->cache_.kSmi, zone());
}
Type* Typer::Visitor::TypeCheckedUint32ToInt32(Node* node) { Type* Typer::Visitor::TypeCheckedUint32ToInt32(Node* node) {
return Type::Signed32(); return Type::Signed32();
} }
......
...@@ -947,6 +947,14 @@ void Verifier::Visitor::Check(Node* node) { ...@@ -947,6 +947,14 @@ void Verifier::Visitor::Check(Node* node) {
CheckValueInputIs(node, 1, Type::Unsigned31()); CheckValueInputIs(node, 1, Type::Unsigned31());
CheckUpperIs(node, Type::Unsigned31()); CheckUpperIs(node, Type::Unsigned31());
break; break;
case IrOpcode::kCheckTaggedSigned:
CheckValueInputIs(node, 0, Type::Any());
CheckUpperIs(node, Type::TaggedSigned());
break;
case IrOpcode::kCheckTaggedPointer:
CheckValueInputIs(node, 0, Type::Any());
CheckUpperIs(node, Type::TaggedPointer());
break;
case IrOpcode::kCheckedUint32ToInt32: case IrOpcode::kCheckedUint32ToInt32:
case IrOpcode::kCheckedFloat64ToInt32: case IrOpcode::kCheckedFloat64ToInt32:
......
...@@ -2302,7 +2302,9 @@ Node* WasmGraphBuilder::BuildAllocateHeapNumberWithValue(Node* value, ...@@ -2302,7 +2302,9 @@ Node* WasmGraphBuilder::BuildAllocateHeapNumberWithValue(Node* value,
Callable callable = CodeFactory::AllocateHeapNumber(jsgraph()->isolate()); Callable callable = CodeFactory::AllocateHeapNumber(jsgraph()->isolate());
Node* target = jsgraph()->HeapConstant(callable.code()); Node* target = jsgraph()->HeapConstant(callable.code());
Node* context = jsgraph()->NoContextConstant(); Node* context = jsgraph()->NoContextConstant();
Node* effect = graph()->NewNode(common->BeginRegion(), graph()->start()); Node* effect =
graph()->NewNode(common->BeginRegion(RegionObservability::kNotObservable),
graph()->start());
if (!allocate_heap_number_operator_.is_set()) { if (!allocate_heap_number_operator_.is_set()) {
CallDescriptor* descriptor = Linkage::GetStubCallDescriptor( CallDescriptor* descriptor = Linkage::GetStubCallDescriptor(
jsgraph()->isolate(), jsgraph()->zone(), callable.descriptor(), 0, jsgraph()->isolate(), jsgraph()->zone(), callable.descriptor(), 0,
......
...@@ -362,15 +362,26 @@ TEST_F(CommonOperatorTest, NumberConstant) { ...@@ -362,15 +362,26 @@ TEST_F(CommonOperatorTest, NumberConstant) {
TEST_F(CommonOperatorTest, BeginRegion) { TEST_F(CommonOperatorTest, BeginRegion) {
const Operator* op = common()->BeginRegion(); {
EXPECT_EQ(1, op->EffectInputCount()); const Operator* op =
EXPECT_EQ(1, OperatorProperties::GetTotalInputCount(op)); common()->BeginRegion(RegionObservability::kObservable);
EXPECT_EQ(0, op->ControlOutputCount()); EXPECT_EQ(1, op->EffectInputCount());
EXPECT_EQ(1, op->EffectOutputCount()); EXPECT_EQ(1, OperatorProperties::GetTotalInputCount(op));
EXPECT_EQ(0, op->ValueOutputCount()); EXPECT_EQ(0, op->ControlOutputCount());
EXPECT_EQ(1, op->EffectOutputCount());
EXPECT_EQ(0, op->ValueOutputCount());
}
{
const Operator* op =
common()->BeginRegion(RegionObservability::kNotObservable);
EXPECT_EQ(1, op->EffectInputCount());
EXPECT_EQ(1, OperatorProperties::GetTotalInputCount(op));
EXPECT_EQ(0, op->ControlOutputCount());
EXPECT_EQ(1, op->EffectOutputCount());
EXPECT_EQ(0, op->ValueOutputCount());
}
} }
TEST_F(CommonOperatorTest, FinishRegion) { TEST_F(CommonOperatorTest, FinishRegion) {
const Operator* op = common()->FinishRegion(); const Operator* op = common()->FinishRegion();
EXPECT_EQ(1, op->ValueInputCount()); EXPECT_EQ(1, op->ValueInputCount());
......
...@@ -48,7 +48,8 @@ class EscapeAnalysisTest : public GraphTest { ...@@ -48,7 +48,8 @@ class EscapeAnalysisTest : public GraphTest {
effect = effect_; effect = effect_;
} }
return effect_ = graph()->NewNode(common()->BeginRegion(), effect); return effect_ = graph()->NewNode(
common()->BeginRegion(RegionObservability::kObservable), effect);
} }
Node* FinishRegion(Node* value, Node* effect = nullptr) { Node* FinishRegion(Node* value, Node* effect = nullptr) {
......
...@@ -333,7 +333,8 @@ TARGET_TEST_F(InstructionSelectorTest, ValueEffect) { ...@@ -333,7 +333,8 @@ TARGET_TEST_F(InstructionSelectorTest, ValueEffect) {
Node* p2 = m2.Parameter(0); Node* p2 = m2.Parameter(0);
m2.Return(m2.AddNode( m2.Return(m2.AddNode(
m2.machine()->Load(MachineType::Int32()), p2, m2.Int32Constant(0), m2.machine()->Load(MachineType::Int32()), p2, m2.Int32Constant(0),
m2.AddNode(m2.common()->BeginRegion(), m2.graph()->start()))); m2.AddNode(m2.common()->BeginRegion(RegionObservability::kObservable),
m2.graph()->start())));
Stream s2 = m2.Build(kAllInstructions); Stream s2 = m2.Build(kAllInstructions);
EXPECT_LE(3U, s1.size()); EXPECT_LE(3U, s1.size());
ASSERT_EQ(s1.size(), s2.size()); ASSERT_EQ(s1.size(), s2.size());
......
...@@ -156,7 +156,8 @@ TEST_P(SimplifiedBufferAccessOperatorTest, LoadBuffer) { ...@@ -156,7 +156,8 @@ TEST_P(SimplifiedBufferAccessOperatorTest, LoadBuffer) {
const Operator* op = simplified.LoadBuffer(access); const Operator* op = simplified.LoadBuffer(access);
EXPECT_EQ(IrOpcode::kLoadBuffer, op->opcode()); EXPECT_EQ(IrOpcode::kLoadBuffer, op->opcode());
EXPECT_EQ(Operator::kNoThrow | Operator::kNoWrite, op->properties()); EXPECT_EQ(Operator::kNoDeopt | Operator::kNoThrow | Operator::kNoWrite,
op->properties());
EXPECT_EQ(access, BufferAccessOf(op)); EXPECT_EQ(access, BufferAccessOf(op));
EXPECT_EQ(3, op->ValueInputCount()); EXPECT_EQ(3, op->ValueInputCount());
...@@ -176,7 +177,8 @@ TEST_P(SimplifiedBufferAccessOperatorTest, StoreBuffer) { ...@@ -176,7 +177,8 @@ TEST_P(SimplifiedBufferAccessOperatorTest, StoreBuffer) {
const Operator* op = simplified.StoreBuffer(access); const Operator* op = simplified.StoreBuffer(access);
EXPECT_EQ(IrOpcode::kStoreBuffer, op->opcode()); EXPECT_EQ(IrOpcode::kStoreBuffer, op->opcode());
EXPECT_EQ(Operator::kNoRead | Operator::kNoThrow, op->properties()); EXPECT_EQ(Operator::kNoDeopt | Operator::kNoRead | Operator::kNoThrow,
op->properties());
EXPECT_EQ(access, BufferAccessOf(op)); EXPECT_EQ(access, BufferAccessOf(op));
EXPECT_EQ(4, op->ValueInputCount()); EXPECT_EQ(4, op->ValueInputCount());
...@@ -258,7 +260,8 @@ TEST_P(SimplifiedElementAccessOperatorTest, LoadElement) { ...@@ -258,7 +260,8 @@ TEST_P(SimplifiedElementAccessOperatorTest, LoadElement) {
const Operator* op = simplified.LoadElement(access); const Operator* op = simplified.LoadElement(access);
EXPECT_EQ(IrOpcode::kLoadElement, op->opcode()); EXPECT_EQ(IrOpcode::kLoadElement, op->opcode());
EXPECT_EQ(Operator::kNoThrow | Operator::kNoWrite, op->properties()); EXPECT_EQ(Operator::kNoDeopt | Operator::kNoThrow | Operator::kNoWrite,
op->properties());
EXPECT_EQ(access, ElementAccessOf(op)); EXPECT_EQ(access, ElementAccessOf(op));
EXPECT_EQ(2, op->ValueInputCount()); EXPECT_EQ(2, op->ValueInputCount());
...@@ -278,7 +281,8 @@ TEST_P(SimplifiedElementAccessOperatorTest, StoreElement) { ...@@ -278,7 +281,8 @@ TEST_P(SimplifiedElementAccessOperatorTest, StoreElement) {
const Operator* op = simplified.StoreElement(access); const Operator* op = simplified.StoreElement(access);
EXPECT_EQ(IrOpcode::kStoreElement, op->opcode()); EXPECT_EQ(IrOpcode::kStoreElement, op->opcode());
EXPECT_EQ(Operator::kNoRead | Operator::kNoThrow, op->properties()); EXPECT_EQ(Operator::kNoDeopt | Operator::kNoRead | Operator::kNoThrow,
op->properties());
EXPECT_EQ(access, ElementAccessOf(op)); EXPECT_EQ(access, ElementAccessOf(op));
EXPECT_EQ(3, op->ValueInputCount()); EXPECT_EQ(3, op->ValueInputCount());
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment