Commit 483291d2 authored by bmeurer's avatar bmeurer Committed by Commit bot

[turbofan] Introduce CheckIf simplified operator.

This adds a new CheckIf operator and changes all direct uses of
DeoptimizeIf and DeoptimizeUnless on the JavaScript level to use
CheckIf (or one of the more concrete check operators) instead.
This way we do not depend on particular frame states, but the
effect/control linearizer will assign an appropriate frame
state instead.

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

Review-Url: https://codereview.chromium.org/2115513002
Cr-Commit-Position: refs/heads/master@{#37423}
parent 5d8cfbbd
......@@ -434,6 +434,9 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node,
case IrOpcode::kCheckNumber:
state = LowerCheckNumber(node, frame_state, *effect, *control);
break;
case IrOpcode::kCheckIf:
state = LowerCheckIf(node, frame_state, *effect, *control);
break;
case IrOpcode::kCheckTaggedPointer:
state = LowerCheckTaggedPointer(node, frame_state, *effect, *control);
break;
......@@ -835,6 +838,20 @@ EffectControlLinearizer::LowerCheckNumber(Node* node, Node* frame_state,
return ValueEffectControl(value, effect, control);
}
EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerCheckIf(Node* node, Node* frame_state,
Node* effect, Node* control) {
Node* value = node->InputAt(0);
control = effect = graph()->NewNode(common()->DeoptimizeUnless(), value,
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::LowerCheckTaggedPointer(Node* node, Node* frame_state,
Node* effect, Node* control) {
......
......@@ -65,6 +65,8 @@ class EffectControlLinearizer {
Node* effect, Node* control);
ValueEffectControl LowerCheckNumber(Node* node, Node* frame_state,
Node* effect, Node* control);
ValueEffectControl LowerCheckIf(Node* node, Node* frame_state, Node* effect,
Node* control);
ValueEffectControl LowerCheckTaggedPointer(Node* node, Node* frame_state,
Node* effect, Node* control);
ValueEffectControl LowerCheckTaggedSigned(Node* node, Node* frame_state,
......
......@@ -6,6 +6,7 @@
#include "src/compiler/js-graph.h"
#include "src/compiler/node-matchers.h"
#include "src/compiler/simplified-operator.h"
#include "src/objects-inl.h"
#include "src/type-feedback-vector-inl.h"
......@@ -220,7 +221,6 @@ Reduction JSCallReducer::ReduceJSCallFunction(Node* node) {
Node* context = NodeProperties::GetContextInput(node);
Node* control = NodeProperties::GetControlInput(node);
Node* effect = NodeProperties::GetEffectInput(node);
Node* frame_state = NodeProperties::FindFrameStateBefore(node);
// Try to specialize JSCallFunction {node}s with constant {target}s.
HeapObjectMatcher m(target);
......@@ -323,16 +323,13 @@ Reduction JSCallReducer::ReduceJSCallFunction(Node* node) {
}
// Check that the {target} is still the {array_function}.
Node* check = graph()->NewNode(
javascript()->StrictEqual(CompareOperationHints::Any()), target,
array_function, context);
control = effect = graph()->NewNode(common()->DeoptimizeUnless(), check,
frame_state, effect, control);
Node* check = graph()->NewNode(simplified()->ReferenceEqual(Type::Any()),
target, array_function);
effect = graph()->NewNode(simplified()->CheckIf(), check, effect, control);
// Turn the {node} into a {JSCreateArray} call.
NodeProperties::ReplaceValueInput(node, array_function, 0);
NodeProperties::ReplaceEffectInput(node, effect);
NodeProperties::ReplaceControlInput(node, control);
return ReduceArrayConstructor(node);
} else if (feedback->IsWeakCell()) {
Handle<WeakCell> cell = Handle<WeakCell>::cast(feedback);
......@@ -341,16 +338,14 @@ Reduction JSCallReducer::ReduceJSCallFunction(Node* node) {
jsgraph()->Constant(handle(cell->value(), isolate()));
// Check that the {target} is still the {target_function}.
Node* check = graph()->NewNode(
javascript()->StrictEqual(CompareOperationHints::Any()), target,
target_function, context);
control = effect = graph()->NewNode(common()->DeoptimizeUnless(), check,
frame_state, effect, control);
Node* check = graph()->NewNode(simplified()->ReferenceEqual(Type::Any()),
target, target_function);
effect =
graph()->NewNode(simplified()->CheckIf(), check, effect, control);
// Specialize the JSCallFunction node to the {target_function}.
NodeProperties::ReplaceValueInput(node, target_function, 0);
NodeProperties::ReplaceEffectInput(node, effect);
NodeProperties::ReplaceControlInput(node, control);
// Try to further reduce the JSCallFunction {node}.
Reduction const reduction = ReduceJSCallFunction(node);
......@@ -371,7 +366,6 @@ Reduction JSCallReducer::ReduceJSCallConstruct(Node* node) {
Node* context = NodeProperties::GetContextInput(node);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
Node* frame_state = NodeProperties::FindFrameStateBefore(node);
// Try to specialize JSCallConstruct {node}s with constant {target}s.
HeapObjectMatcher m(target);
......@@ -445,15 +439,12 @@ Reduction JSCallReducer::ReduceJSCallConstruct(Node* node) {
}
// Check that the {target} is still the {array_function}.
Node* check = graph()->NewNode(
javascript()->StrictEqual(CompareOperationHints::Any()), target,
array_function, context);
control = effect = graph()->NewNode(common()->DeoptimizeUnless(), check,
frame_state, effect, control);
Node* check = graph()->NewNode(simplified()->ReferenceEqual(Type::Any()),
target, array_function);
effect = graph()->NewNode(simplified()->CheckIf(), check, effect, control);
// Turn the {node} into a {JSCreateArray} call.
NodeProperties::ReplaceEffectInput(node, effect);
NodeProperties::ReplaceControlInput(node, control);
for (int i = arity; i > 0; --i) {
NodeProperties::ReplaceValueInput(
node, NodeProperties::GetValueInput(node, i), i + 1);
......@@ -468,16 +459,14 @@ Reduction JSCallReducer::ReduceJSCallConstruct(Node* node) {
jsgraph()->Constant(handle(cell->value(), isolate()));
// Check that the {target} is still the {target_function}.
Node* check = graph()->NewNode(
javascript()->StrictEqual(CompareOperationHints::Any()), target,
target_function, context);
control = effect = graph()->NewNode(common()->DeoptimizeUnless(), check,
frame_state, effect, control);
Node* check = graph()->NewNode(simplified()->ReferenceEqual(Type::Any()),
target, target_function);
effect =
graph()->NewNode(simplified()->CheckIf(), check, effect, control);
// Specialize the JSCallConstruct node to the {target_function}.
NodeProperties::ReplaceValueInput(node, target_function, 0);
NodeProperties::ReplaceEffectInput(node, effect);
NodeProperties::ReplaceControlInput(node, control);
if (target == new_target) {
NodeProperties::ReplaceValueInput(node, target_function, arity + 1);
}
......@@ -514,6 +503,10 @@ JSOperatorBuilder* JSCallReducer::javascript() const {
return jsgraph()->javascript();
}
SimplifiedOperatorBuilder* JSCallReducer::simplified() const {
return jsgraph()->simplified();
}
} // namespace compiler
} // namespace internal
} // namespace v8
......@@ -16,7 +16,7 @@ namespace compiler {
class CommonOperatorBuilder;
class JSGraph;
class JSOperatorBuilder;
class SimplifiedOperatorBuilder;
// Performs strength reduction on {JSCallConstruct} and {JSCallFunction} nodes,
// which might allow inlining or other optimizations to be performed afterwards.
......@@ -52,6 +52,7 @@ class JSCallReducer final : public Reducer {
MaybeHandle<Context> native_context() const { return native_context_; }
CommonOperatorBuilder* common() const;
JSOperatorBuilder* javascript() const;
SimplifiedOperatorBuilder* simplified() const;
JSGraph* const jsgraph_;
Flags const flags_;
......
......@@ -133,7 +133,6 @@ Reduction JSGlobalObjectSpecialization::ReduceJSStoreGlobal(Node* node) {
Node* value = NodeProperties::GetValueInput(node, 0);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
Node* frame_state = NodeProperties::FindFrameStateBefore(node);
// Retrieve the global object from the given {node}.
Handle<JSGlobalObject> global_object;
......@@ -173,20 +172,19 @@ Reduction JSGlobalObjectSpecialization::ReduceJSStoreGlobal(Node* node) {
Node* check =
graph()->NewNode(simplified()->ReferenceEqual(Type::Tagged()), value,
jsgraph()->Constant(property_cell_value));
control = effect = graph()->NewNode(common()->DeoptimizeUnless(), check,
frame_state, effect, control);
effect =
graph()->NewNode(simplified()->CheckIf(), check, effect, control);
break;
}
case PropertyCellType::kConstantType: {
// Record a code dependency on the cell, and just deoptimize if the new
// values' type doesn't match the type of the previous value in the cell.
dependencies()->AssumePropertyCell(property_cell);
Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), value);
Type* property_cell_value_type = Type::TaggedSigned();
Type* property_cell_value_type;
if (property_cell_value->IsHeapObject()) {
// Deoptimize if the {value} is a Smi.
control = effect = graph()->NewNode(common()->DeoptimizeIf(), check,
frame_state, effect, control);
// Check that the {value} is a HeapObject.
value = effect = graph()->NewNode(simplified()->CheckTaggedPointer(),
value, effect, control);
// Load the {value} map check against the {property_cell} map.
Node* value_map = effect =
......@@ -194,13 +192,18 @@ Reduction JSGlobalObjectSpecialization::ReduceJSStoreGlobal(Node* node) {
value, effect, control);
Handle<Map> property_cell_value_map(
Handle<HeapObject>::cast(property_cell_value)->map(), isolate());
check = graph()->NewNode(
Node* check = graph()->NewNode(
simplified()->ReferenceEqual(Type::Any()), value_map,
jsgraph()->HeapConstant(property_cell_value_map));
effect =
graph()->NewNode(simplified()->CheckIf(), check, effect, control);
property_cell_value_type = Type::TaggedPointer();
} else {
// Check that the {value} is a Smi.
value = effect = graph()->NewNode(simplified()->CheckTaggedSigned(),
value, effect, control);
property_cell_value_type = Type::TaggedSigned();
}
control = effect = graph()->NewNode(common()->DeoptimizeUnless(), check,
frame_state, effect, control);
effect = graph()->NewNode(
simplified()->StoreField(
AccessBuilder::ForPropertyCellValue(property_cell_value_type)),
......
......@@ -80,7 +80,6 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
Node* receiver = NodeProperties::GetValueInput(node, 0);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
Node* frame_state = NodeProperties::FindFrameStateBefore(node);
// Not much we can do if deoptimization support is disabled.
if (!(flags() & kDeoptimizationEnabled)) return NoChange();
......@@ -111,8 +110,7 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
if (index != nullptr) {
Node* check = graph()->NewNode(simplified()->ReferenceEqual(Type::Name()),
index, jsgraph()->HeapConstant(name));
control = effect = graph()->NewNode(common()->DeoptimizeUnless(), check,
frame_state, effect, control);
effect = graph()->NewNode(simplified()->CheckIf(), check, effect, control);
}
// Check if {receiver} may be a number.
......@@ -158,9 +156,9 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
if (receiver_type->Is(Type::String())) {
Node* check = graph()->NewNode(simplified()->ObjectIsString(), receiver);
if (j == access_infos.size() - 1) {
this_control = this_effect =
graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state,
this_effect, fallthrough_control);
this_effect = graph()->NewNode(simplified()->CheckIf(), check,
this_effect, fallthrough_control);
this_control = fallthrough_control;
fallthrough_control = nullptr;
} else {
Node* branch =
......@@ -181,11 +179,10 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
graph()->NewNode(simplified()->ReferenceEqual(Type::Internal()),
receiver_map, jsgraph()->Constant(map));
if (--num_classes == 0 && j == access_infos.size() - 1) {
Node* deoptimize =
graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state,
this_effect, fallthrough_control);
this_controls.push_back(deoptimize);
this_effects.push_back(deoptimize);
check = graph()->NewNode(simplified()->CheckIf(), check, this_effect,
fallthrough_control);
this_controls.push_back(fallthrough_control);
this_effects.push_back(check);
fallthrough_control = nullptr;
} else {
Node* branch =
......@@ -237,9 +234,8 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
if (access_mode == AccessMode::kStore) {
Node* check = graph()->NewNode(
simplified()->ReferenceEqual(Type::Tagged()), value, this_value);
this_control = this_effect =
graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state,
this_effect, this_control);
this_effect = graph()->NewNode(simplified()->CheckIf(), check,
this_effect, this_control);
}
} else {
DCHECK(access_info.IsDataField());
......@@ -331,9 +327,8 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
Node* check = graph()->NewNode(
simplified()->ReferenceEqual(Type::Internal()), this_value_map,
jsgraph()->Constant(field_type->Classes().Current()));
this_control = this_effect =
graph()->NewNode(common()->DeoptimizeUnless(), check,
frame_state, this_effect, this_control);
this_effect = graph()->NewNode(simplified()->CheckIf(), check,
this_effect, this_control);
} else {
DCHECK_EQ(0, field_type->NumClasses());
}
......@@ -564,11 +559,10 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
// TODO(turbofan): This is ugly as hell! We should probably introduce
// macro-ish operators for property access that encapsulate this whole
// mess.
Node* deoptimize =
graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state,
effect, fallthrough_control);
this_controls.push_back(deoptimize);
this_effects.push_back(deoptimize);
check = graph()->NewNode(simplified()->CheckIf(), check, effect,
fallthrough_control);
this_controls.push_back(fallthrough_control);
this_effects.push_back(check);
fallthrough_control = nullptr;
} else {
Node* branch =
......@@ -593,9 +587,10 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
simplified()->ReferenceEqual(Type::Any()), receiver_map,
jsgraph()->HeapConstant(transition_source));
if (--num_transitions == 0 && j == access_infos.size() - 1) {
transition_control = transition_effect =
graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state,
transition_effect =
graph()->NewNode(simplified()->CheckIf(), check,
transition_effect, fallthrough_control);
transition_control = fallthrough_control;
fallthrough_control = nullptr;
} else {
Node* branch =
......@@ -680,9 +675,8 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
Node* check = graph()->NewNode(
simplified()->ReferenceEqual(Type::Any()), this_elements_map,
jsgraph()->HeapConstant(factory()->fixed_array_map()));
this_control = this_effect =
graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state,
this_effect, this_control);
this_effect = graph()->NewNode(simplified()->CheckIf(), check,
this_effect, this_control);
}
// Load the length of the {receiver}.
......
......@@ -172,6 +172,10 @@ struct HeapObjectMatcher final
: public ValueMatcher<Handle<HeapObject>, IrOpcode::kHeapConstant> {
explicit HeapObjectMatcher(Node* node)
: ValueMatcher<Handle<HeapObject>, IrOpcode::kHeapConstant>(node) {}
bool Is(Handle<HeapObject> const& value) const {
return this->HasValue() && this->Value().address() == value.address();
}
};
......
......@@ -248,6 +248,7 @@
V(StringFromCharCode) \
V(StringToNumber) \
V(CheckBounds) \
V(CheckIf) \
V(CheckNumber) \
V(CheckTaggedPointer) \
V(CheckTaggedSigned) \
......
......@@ -19,6 +19,7 @@ Reduction RedundancyElimination::Reduce(Node* node) {
switch (node->opcode()) {
case IrOpcode::kCheckBounds:
case IrOpcode::kCheckFloat64Hole:
case IrOpcode::kCheckIf:
case IrOpcode::kCheckNumber:
case IrOpcode::kCheckTaggedHole:
case IrOpcode::kCheckTaggedPointer:
......
......@@ -1692,14 +1692,24 @@ class RepresentationSelector {
UseInfo::TruncatingWord32(), MachineRepresentation::kWord32);
return;
}
case IrOpcode::kCheckIf: {
ProcessInput(node, 0, UseInfo::Bool());
ProcessRemainingInputs(node, 1);
SetOutput(node, MachineRepresentation::kNone);
return;
}
case IrOpcode::kCheckNumber: {
if (InputIs(node, Type::Number())) {
if (truncation.TruncatesToWord32()) {
VisitUnop(node, UseInfo::TruncatingWord32(),
MachineRepresentation::kWord32);
} else {
VisitUnop(node, UseInfo::TruncatingFloat64(),
MachineRepresentation::kFloat64);
// TODO(jarin,bmeurer): We need to go to Tagged here, because
// otherwise we cannot distinguish the hole NaN (which might need to
// be treated as undefined). We should have a dedicated Type for
// that at some point, and maybe even a dedicated truncation.
VisitUnop(node, UseInfo::AnyTagged(),
MachineRepresentation::kTagged);
}
if (lower()) DeferReplacement(node, node->InputAt(0));
} else {
......
......@@ -43,9 +43,8 @@ Reduction SimplifiedOperatorReducer::Reduce(Node* node) {
switch (node->opcode()) {
case IrOpcode::kBooleanNot: {
HeapObjectMatcher m(node->InputAt(0));
if (m.HasValue()) {
return Replace(jsgraph()->BooleanConstant(!m.Value()->BooleanValue()));
}
if (m.Is(factory()->true_value())) return ReplaceBoolean(false);
if (m.Is(factory()->false_value())) return ReplaceBoolean(true);
if (m.IsBooleanNot()) return Replace(m.InputAt(0));
break;
}
......@@ -127,6 +126,14 @@ Reduction SimplifiedOperatorReducer::Reduce(Node* node) {
}
break;
}
case IrOpcode::kCheckIf: {
HeapObjectMatcher m(node->InputAt(0));
if (m.Is(factory()->true_value())) {
Node* const effect = NodeProperties::GetEffectInput(node);
return Replace(effect);
}
break;
}
case IrOpcode::kCheckTaggedPointer: {
Node* const input = node->InputAt(0);
if (DecideObjectIsSmi(input) == Decision::kFalse) {
......@@ -203,9 +210,15 @@ Reduction SimplifiedOperatorReducer::ReplaceNumber(int32_t value) {
return Replace(jsgraph()->Constant(value));
}
Factory* SimplifiedOperatorReducer::factory() const {
return isolate()->factory();
}
Graph* SimplifiedOperatorReducer::graph() const { return jsgraph()->graph(); }
Isolate* SimplifiedOperatorReducer::isolate() const {
return jsgraph()->isolate();
}
MachineOperatorBuilder* SimplifiedOperatorReducer::machine() const {
return jsgraph()->machine();
......
......@@ -9,6 +9,11 @@
namespace v8 {
namespace internal {
// Forward declarations.
class Factory;
class Isolate;
namespace compiler {
// Forward declarations.
......@@ -36,7 +41,9 @@ class SimplifiedOperatorReducer final : public AdvancedReducer {
Reduction ReplaceNumber(double value);
Reduction ReplaceNumber(int32_t value);
Factory* factory() const;
Graph* graph() const;
Isolate* isolate() const;
JSGraph* jsgraph() const { return jsgraph_; }
MachineOperatorBuilder* machine() const;
SimplifiedOperatorBuilder* simplified() const;
......
......@@ -305,16 +305,18 @@ CompareOperationHints::Hint CompareOperationHintOf(const Operator* op) {
V(SpeculativeNumberMultiply) \
V(SpeculativeNumberModulus)
#define CHECKED_OP_LIST(V) \
V(CheckNumber, 1) \
V(CheckTaggedPointer, 1) \
V(CheckTaggedSigned, 1) \
V(CheckedInt32Add, 2) \
V(CheckedInt32Sub, 2) \
V(CheckedUint32ToInt32, 1) \
V(CheckedFloat64ToInt32, 1) \
V(CheckedTaggedToInt32, 1) \
V(CheckedTaggedToFloat64, 1)
#define CHECKED_OP_LIST(V) \
V(CheckBounds, 2, 1) \
V(CheckIf, 1, 0) \
V(CheckNumber, 1, 1) \
V(CheckTaggedPointer, 1, 1) \
V(CheckTaggedSigned, 1, 1) \
V(CheckedInt32Add, 2, 1) \
V(CheckedInt32Sub, 2, 1) \
V(CheckedUint32ToInt32, 1, 1) \
V(CheckedFloat64ToInt32, 1, 1) \
V(CheckedTaggedToInt32, 1, 1) \
V(CheckedTaggedToFloat64, 1, 1)
struct SimplifiedOperatorGlobalCache final {
#define PURE(Name, properties, input_count) \
......@@ -327,13 +329,13 @@ struct SimplifiedOperatorGlobalCache final {
PURE_OP_LIST(PURE)
#undef PURE
#define CHECKED(Name, value_input_count) \
struct Name##Operator final : public Operator { \
Name##Operator() \
: Operator(IrOpcode::k##Name, \
Operator::kFoldable | Operator::kNoThrow, #Name, \
value_input_count, 1, 1, 1, 1, 0) {} \
}; \
#define CHECKED(Name, value_input_count, value_output_count) \
struct Name##Operator final : public Operator { \
Name##Operator() \
: Operator(IrOpcode::k##Name, \
Operator::kFoldable | Operator::kNoThrow, #Name, \
value_input_count, 1, 1, value_output_count, 1, 0) {} \
}; \
Name##Operator k##Name;
CHECKED_OP_LIST(CHECKED)
#undef CHECKED
......@@ -412,7 +414,7 @@ SimplifiedOperatorBuilder::SimplifiedOperatorBuilder(Zone* zone)
PURE_OP_LIST(GET_FROM_CACHE)
#undef GET_FROM_CACHE
#define GET_FROM_CACHE(Name, value_input_count) \
#define GET_FROM_CACHE(Name, value_input_count, value_output_count) \
const Operator* SimplifiedOperatorBuilder::Name() { return &cache_.k##Name; }
CHECKED_OP_LIST(GET_FROM_CACHE)
#undef GET_FROM_CACHE
......@@ -447,13 +449,6 @@ const Operator* SimplifiedOperatorBuilder::ReferenceEqual(Type* type) {
"ReferenceEqual", 2, 0, 0, 1, 0, 0);
}
const Operator* SimplifiedOperatorBuilder::CheckBounds() {
// TODO(bmeurer): Cache this operator. Make it pure!
return new (zone())
Operator(IrOpcode::kCheckBounds, Operator::kFoldable | Operator::kNoThrow,
"CheckBounds", 2, 1, 1, 1, 1, 0);
}
const Operator* SimplifiedOperatorBuilder::Allocate(PretenureFlag pretenure) {
switch (pretenure) {
case NOT_TENURED:
......
......@@ -238,6 +238,7 @@ class SimplifiedOperatorBuilder final : public ZoneObject {
const Operator* TruncateTaggedToWord32();
const Operator* TruncateTaggedToFloat64();
const Operator* CheckIf();
const Operator* CheckBounds();
const Operator* CheckNumber();
const Operator* CheckTaggedPointer();
......
......@@ -1746,6 +1746,11 @@ Type* Typer::Visitor::TypeCheckNumber(Node* node) {
return Type::Intersect(arg, Type::Number(), zone());
}
Type* Typer::Visitor::TypeCheckIf(Node* node) {
UNREACHABLE();
return nullptr;
}
Type* Typer::Visitor::TypeCheckTaggedPointer(Node* node) {
Type* arg = Operand(node, 0);
return Type::Intersect(arg, Type::TaggedPointer(), zone());
......
......@@ -948,6 +948,10 @@ void Verifier::Visitor::Check(Node* node) {
CheckValueInputIs(node, 0, Type::Any());
CheckUpperIs(node, Type::Number());
break;
case IrOpcode::kCheckIf:
CheckValueInputIs(node, 0, Type::Boolean());
CheckNotTyped(node);
break;
case IrOpcode::kCheckTaggedSigned:
CheckValueInputIs(node, 0, Type::Any());
CheckUpperIs(node, Type::TaggedSigned());
......
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