[turbofan] Remove obsolete LoadBuffer and StoreBuffer operators.
These operators were only used by the old asm.js pipeline (with fullcodegen and the AstGraphBuilder). When going through the new pipeline, accesses to TypedArrays are handled by the native context specialization during inlining. Bug: v8:6409 Change-Id: Ib9b888c0b96f297a335580ee42dfa951bde566be Reviewed-on: https://chromium-review.googlesource.com/612347 Reviewed-by: Jaroslav Sevcik <jarin@chromium.org> Commit-Queue: Benedikt Meurer <bmeurer@chromium.org> Cr-Commit-Position: refs/heads/master@{#47322}
This commit is contained in:
parent
438a845c52
commit
94830f4b1b
@ -411,13 +411,7 @@ JSTypedLowering::JSTypedLowering(Editor* editor,
|
||||
Type::Union(Type::SymbolOrReceiver(), empty_string_type_,
|
||||
graph()->zone()),
|
||||
graph()->zone())),
|
||||
type_cache_(TypeCache::Get()) {
|
||||
for (size_t k = 0; k < arraysize(shifted_int32_ranges_); ++k) {
|
||||
double min = kMinInt / (1 << k);
|
||||
double max = kMaxInt / (1 << k);
|
||||
shifted_int32_ranges_[k] = Type::Range(min, max, graph()->zone());
|
||||
}
|
||||
}
|
||||
type_cache_(TypeCache::Get()) {}
|
||||
|
||||
Reduction JSTypedLowering::ReduceSpeculativeNumberAdd(Node* node) {
|
||||
JSBinopReduction r(this, node);
|
||||
@ -1135,131 +1129,6 @@ Reduction JSTypedLowering::ReduceJSLoadNamed(Node* node) {
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
Reduction JSTypedLowering::ReduceJSLoadProperty(Node* node) {
|
||||
Node* key = NodeProperties::GetValueInput(node, 1);
|
||||
Node* base = NodeProperties::GetValueInput(node, 0);
|
||||
Type* key_type = NodeProperties::GetType(key);
|
||||
HeapObjectMatcher mbase(base);
|
||||
if (mbase.HasValue() && mbase.Value()->IsJSTypedArray()) {
|
||||
Handle<JSTypedArray> const array =
|
||||
Handle<JSTypedArray>::cast(mbase.Value());
|
||||
if (!array->GetBuffer()->was_neutered() &&
|
||||
!array->GetBuffer()->is_wasm_buffer()) {
|
||||
array->GetBuffer()->set_is_neuterable(false);
|
||||
BufferAccess const access(array->type());
|
||||
size_t const k =
|
||||
ElementSizeLog2Of(access.machine_type().representation());
|
||||
double const byte_length = array->byte_length()->Number();
|
||||
CHECK_LT(k, arraysize(shifted_int32_ranges_));
|
||||
if (key_type->Is(shifted_int32_ranges_[k]) && byte_length <= kMaxInt) {
|
||||
// JSLoadProperty(typed-array, int32)
|
||||
Handle<FixedTypedArrayBase> elements =
|
||||
Handle<FixedTypedArrayBase>::cast(handle(array->elements()));
|
||||
Node* buffer = jsgraph()->PointerConstant(elements->external_pointer());
|
||||
Node* length = jsgraph()->Constant(byte_length);
|
||||
Node* effect = NodeProperties::GetEffectInput(node);
|
||||
Node* control = NodeProperties::GetControlInput(node);
|
||||
// Check if we can avoid the bounds check.
|
||||
if (key_type->Min() >= 0 && key_type->Max() < array->length_value()) {
|
||||
Node* load = graph()->NewNode(
|
||||
simplified()->LoadElement(
|
||||
AccessBuilder::ForTypedArrayElement(array->type(), true)),
|
||||
buffer, key, effect, control);
|
||||
ReplaceWithValue(node, load, load);
|
||||
return Replace(load);
|
||||
}
|
||||
// Compute byte offset.
|
||||
Node* offset =
|
||||
(k == 0) ? key : graph()->NewNode(
|
||||
simplified()->NumberShiftLeft(), key,
|
||||
jsgraph()->Constant(static_cast<double>(k)));
|
||||
Node* load = graph()->NewNode(simplified()->LoadBuffer(access), buffer,
|
||||
offset, length, effect, control);
|
||||
ReplaceWithValue(node, load, load);
|
||||
return Replace(load);
|
||||
}
|
||||
}
|
||||
}
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
Reduction JSTypedLowering::ReduceJSStoreProperty(Node* node) {
|
||||
Node* key = NodeProperties::GetValueInput(node, 1);
|
||||
Node* base = NodeProperties::GetValueInput(node, 0);
|
||||
Node* value = NodeProperties::GetValueInput(node, 2);
|
||||
Type* key_type = NodeProperties::GetType(key);
|
||||
Type* value_type = NodeProperties::GetType(value);
|
||||
|
||||
if (!value_type->Is(Type::PlainPrimitive())) return NoChange();
|
||||
|
||||
HeapObjectMatcher mbase(base);
|
||||
if (mbase.HasValue() && mbase.Value()->IsJSTypedArray()) {
|
||||
Handle<JSTypedArray> const array =
|
||||
Handle<JSTypedArray>::cast(mbase.Value());
|
||||
if (!array->GetBuffer()->was_neutered() &&
|
||||
!array->GetBuffer()->is_wasm_buffer()) {
|
||||
array->GetBuffer()->set_is_neuterable(false);
|
||||
BufferAccess const access(array->type());
|
||||
size_t const k =
|
||||
ElementSizeLog2Of(access.machine_type().representation());
|
||||
double const byte_length = array->byte_length()->Number();
|
||||
CHECK_LT(k, arraysize(shifted_int32_ranges_));
|
||||
if (access.external_array_type() != kExternalUint8ClampedArray &&
|
||||
key_type->Is(shifted_int32_ranges_[k]) && byte_length <= kMaxInt) {
|
||||
// JSLoadProperty(typed-array, int32)
|
||||
Handle<FixedTypedArrayBase> elements =
|
||||
Handle<FixedTypedArrayBase>::cast(handle(array->elements()));
|
||||
Node* buffer = jsgraph()->PointerConstant(elements->external_pointer());
|
||||
Node* length = jsgraph()->Constant(byte_length);
|
||||
Node* effect = NodeProperties::GetEffectInput(node);
|
||||
Node* control = NodeProperties::GetControlInput(node);
|
||||
// Convert to a number first.
|
||||
if (!value_type->Is(Type::Number())) {
|
||||
Reduction number_reduction = ReduceJSToNumberInput(value);
|
||||
if (number_reduction.Changed()) {
|
||||
value = number_reduction.replacement();
|
||||
} else {
|
||||
value =
|
||||
graph()->NewNode(simplified()->PlainPrimitiveToNumber(), value);
|
||||
}
|
||||
}
|
||||
// Check if we can avoid the bounds check.
|
||||
if (key_type->Min() >= 0 && key_type->Max() < array->length_value()) {
|
||||
RelaxControls(node);
|
||||
node->ReplaceInput(0, buffer);
|
||||
DCHECK_EQ(key, node->InputAt(1));
|
||||
node->ReplaceInput(2, value);
|
||||
node->ReplaceInput(3, effect);
|
||||
node->ReplaceInput(4, control);
|
||||
node->TrimInputCount(5);
|
||||
NodeProperties::ChangeOp(
|
||||
node,
|
||||
simplified()->StoreElement(
|
||||
AccessBuilder::ForTypedArrayElement(array->type(), true)));
|
||||
return Changed(node);
|
||||
}
|
||||
// Compute byte offset.
|
||||
Node* offset =
|
||||
(k == 0) ? key : graph()->NewNode(
|
||||
simplified()->NumberShiftLeft(), key,
|
||||
jsgraph()->Constant(static_cast<double>(k)));
|
||||
// Turn into a StoreBuffer operation.
|
||||
RelaxControls(node);
|
||||
node->ReplaceInput(0, buffer);
|
||||
node->ReplaceInput(1, offset);
|
||||
node->ReplaceInput(2, length);
|
||||
node->ReplaceInput(3, value);
|
||||
node->ReplaceInput(4, effect);
|
||||
node->ReplaceInput(5, control);
|
||||
node->TrimInputCount(6);
|
||||
NodeProperties::ChangeOp(node, simplified()->StoreBuffer(access));
|
||||
return Changed(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
Reduction JSTypedLowering::ReduceJSHasInPrototypeChain(Node* node) {
|
||||
DCHECK_EQ(IrOpcode::kJSHasInPrototypeChain, node->opcode());
|
||||
Node* value = NodeProperties::GetValueInput(node, 0);
|
||||
@ -2264,10 +2133,6 @@ Reduction JSTypedLowering::Reduce(Node* node) {
|
||||
return ReduceJSTypeOf(node);
|
||||
case IrOpcode::kJSLoadNamed:
|
||||
return ReduceJSLoadNamed(node);
|
||||
case IrOpcode::kJSLoadProperty:
|
||||
return ReduceJSLoadProperty(node);
|
||||
case IrOpcode::kJSStoreProperty:
|
||||
return ReduceJSStoreProperty(node);
|
||||
case IrOpcode::kJSLoadContext:
|
||||
return ReduceJSLoadContext(node);
|
||||
case IrOpcode::kJSStoreContext:
|
||||
|
@ -44,8 +44,6 @@ class V8_EXPORT_PRIVATE JSTypedLowering final
|
||||
Reduction ReduceJSAdd(Node* node);
|
||||
Reduction ReduceJSComparison(Node* node);
|
||||
Reduction ReduceJSLoadNamed(Node* node);
|
||||
Reduction ReduceJSLoadProperty(Node* node);
|
||||
Reduction ReduceJSStoreProperty(Node* node);
|
||||
Reduction ReduceJSHasInPrototypeChain(Node* node);
|
||||
Reduction ReduceJSOrdinaryHasInstance(Node* node);
|
||||
Reduction ReduceJSLoadContext(Node* node);
|
||||
@ -102,7 +100,6 @@ class V8_EXPORT_PRIVATE JSTypedLowering final
|
||||
CompilationDependencies* dependencies_;
|
||||
JSGraph* jsgraph_;
|
||||
Type* empty_string_type_;
|
||||
Type* shifted_int32_ranges_[4];
|
||||
Type* pointer_comparable_type_;
|
||||
TypeCache const& type_cache_;
|
||||
};
|
||||
|
@ -1081,7 +1081,6 @@ LoadElimination::AbstractState const* LoadElimination::ComputeLoopState(
|
||||
state = state->KillElement(object, index, zone());
|
||||
break;
|
||||
}
|
||||
case IrOpcode::kStoreBuffer:
|
||||
case IrOpcode::kStoreTypedElement: {
|
||||
// Doesn't affect anything we track with the state currently.
|
||||
break;
|
||||
|
@ -338,11 +338,9 @@
|
||||
V(ConvertTaggedHoleToUndefined) \
|
||||
V(Allocate) \
|
||||
V(LoadField) \
|
||||
V(LoadBuffer) \
|
||||
V(LoadElement) \
|
||||
V(LoadTypedElement) \
|
||||
V(StoreField) \
|
||||
V(StoreBuffer) \
|
||||
V(StoreElement) \
|
||||
V(StoreTypedElement) \
|
||||
V(TransitionAndStoreElement) \
|
||||
|
@ -2492,53 +2492,6 @@ class RepresentationSelector {
|
||||
}
|
||||
return;
|
||||
}
|
||||
case IrOpcode::kLoadBuffer: {
|
||||
if (truncation.IsUnused()) return VisitUnused(node);
|
||||
BufferAccess access = BufferAccessOf(node->op());
|
||||
ProcessInput(node, 0, UseInfo::PointerInt()); // buffer
|
||||
ProcessInput(node, 1, UseInfo::TruncatingWord32()); // offset
|
||||
ProcessInput(node, 2, UseInfo::TruncatingWord32()); // length
|
||||
ProcessRemainingInputs(node, 3);
|
||||
|
||||
MachineRepresentation output;
|
||||
if (truncation.IdentifiesUndefinedAndNaN()) {
|
||||
if (truncation.IdentifiesUndefinedAndZero()) {
|
||||
// If undefined is truncated to a non-NaN number, we can use
|
||||
// the load's representation.
|
||||
output = access.machine_type().representation();
|
||||
} else {
|
||||
// If undefined is truncated to a number, but the use can
|
||||
// observe NaN, we need to output at least the float32
|
||||
// representation.
|
||||
if (access.machine_type().representation() ==
|
||||
MachineRepresentation::kFloat32) {
|
||||
output = access.machine_type().representation();
|
||||
} else {
|
||||
output = MachineRepresentation::kFloat64;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// If undefined is not truncated away, we need to have the tagged
|
||||
// representation.
|
||||
output = MachineRepresentation::kTagged;
|
||||
}
|
||||
SetOutput(node, output);
|
||||
if (lower()) lowering->DoLoadBuffer(node, output, changer_);
|
||||
return;
|
||||
}
|
||||
case IrOpcode::kStoreBuffer: {
|
||||
BufferAccess access = BufferAccessOf(node->op());
|
||||
ProcessInput(node, 0, UseInfo::PointerInt()); // buffer
|
||||
ProcessInput(node, 1, UseInfo::TruncatingWord32()); // offset
|
||||
ProcessInput(node, 2, UseInfo::TruncatingWord32()); // length
|
||||
ProcessInput(node, 3,
|
||||
TruncatingUseInfoFromRepresentation(
|
||||
access.machine_type().representation())); // value
|
||||
ProcessRemainingInputs(node, 4);
|
||||
SetOutput(node, MachineRepresentation::kNone);
|
||||
if (lower()) lowering->DoStoreBuffer(node);
|
||||
return;
|
||||
}
|
||||
case IrOpcode::kLoadElement: {
|
||||
if (truncation.IsUnused()) return VisitUnused(node);
|
||||
ElementAccess access = ElementAccessOf(node->op());
|
||||
@ -3220,75 +3173,6 @@ void SimplifiedLowering::DoJSToNumberTruncatesToWord32(
|
||||
selector->DeferReplacement(node, value);
|
||||
}
|
||||
|
||||
void SimplifiedLowering::DoLoadBuffer(Node* node,
|
||||
MachineRepresentation output_rep,
|
||||
RepresentationChanger* changer) {
|
||||
DCHECK_EQ(IrOpcode::kLoadBuffer, node->opcode());
|
||||
DCHECK_NE(MachineRepresentation::kNone, output_rep);
|
||||
MachineType const access_type = BufferAccessOf(node->op()).machine_type();
|
||||
if (output_rep != access_type.representation()) {
|
||||
Node* const buffer = node->InputAt(0);
|
||||
Node* const offset = node->InputAt(1);
|
||||
Node* const length = node->InputAt(2);
|
||||
Node* const effect = node->InputAt(3);
|
||||
Node* const control = node->InputAt(4);
|
||||
Node* const index =
|
||||
machine()->Is64()
|
||||
? graph()->NewNode(machine()->ChangeUint32ToUint64(), offset)
|
||||
: offset;
|
||||
|
||||
Node* check = graph()->NewNode(machine()->Uint32LessThan(), offset, length);
|
||||
Node* branch =
|
||||
graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
|
||||
|
||||
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
|
||||
Node* etrue = graph()->NewNode(machine()->Load(access_type), buffer, index,
|
||||
effect, if_true);
|
||||
Type* element_type =
|
||||
Type::Intersect(NodeProperties::GetType(node), Type::Number(), zone());
|
||||
Node* vtrue = changer->GetRepresentationFor(
|
||||
etrue, access_type.representation(), element_type, node,
|
||||
UseInfo(output_rep, Truncation::None()));
|
||||
|
||||
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
|
||||
Node* efalse = effect;
|
||||
Node* vfalse;
|
||||
if (output_rep == MachineRepresentation::kTagged) {
|
||||
vfalse = jsgraph()->UndefinedConstant();
|
||||
} else if (output_rep == MachineRepresentation::kFloat64) {
|
||||
vfalse =
|
||||
jsgraph()->Float64Constant(std::numeric_limits<double>::quiet_NaN());
|
||||
} else if (output_rep == MachineRepresentation::kFloat32) {
|
||||
vfalse =
|
||||
jsgraph()->Float32Constant(std::numeric_limits<float>::quiet_NaN());
|
||||
} else {
|
||||
vfalse = jsgraph()->Int32Constant(0);
|
||||
}
|
||||
|
||||
Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
|
||||
Node* ephi = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, merge);
|
||||
|
||||
// Replace effect uses of {node} with the {ephi}.
|
||||
NodeProperties::ReplaceUses(node, node, ephi);
|
||||
|
||||
// Turn the {node} into a Phi.
|
||||
node->ReplaceInput(0, vtrue);
|
||||
node->ReplaceInput(1, vfalse);
|
||||
node->ReplaceInput(2, merge);
|
||||
node->TrimInputCount(3);
|
||||
NodeProperties::ChangeOp(node, common()->Phi(output_rep, 2));
|
||||
} else {
|
||||
NodeProperties::ChangeOp(node, machine()->CheckedLoad(access_type));
|
||||
}
|
||||
}
|
||||
|
||||
void SimplifiedLowering::DoStoreBuffer(Node* node) {
|
||||
DCHECK_EQ(IrOpcode::kStoreBuffer, node->opcode());
|
||||
MachineRepresentation const rep =
|
||||
BufferAccessOf(node->op()).machine_type().representation();
|
||||
NodeProperties::ChangeOp(node, machine()->CheckedStore(rep));
|
||||
}
|
||||
|
||||
Node* SimplifiedLowering::Float64Round(Node* const node) {
|
||||
Node* const one = jsgraph()->Float64Constant(1.0);
|
||||
Node* const one_half = jsgraph()->Float64Constant(0.5);
|
||||
|
@ -34,11 +34,6 @@ class SimplifiedLowering final {
|
||||
RepresentationSelector* selector);
|
||||
void DoJSToNumberTruncatesToWord32(Node* node,
|
||||
RepresentationSelector* selector);
|
||||
// TODO(turbofan): The representation can be removed once the result of the
|
||||
// representation analysis is stored in the node bounds.
|
||||
void DoLoadBuffer(Node* node, MachineRepresentation rep,
|
||||
RepresentationChanger* changer);
|
||||
void DoStoreBuffer(Node* node);
|
||||
void DoShift(Node* node, Operator const* op, Type* rhs_type);
|
||||
void DoStringToNumber(Node* node);
|
||||
void DoIntegral32ToBit(Node* node);
|
||||
|
@ -29,63 +29,6 @@ std::ostream& operator<<(std::ostream& os, BaseTaggedness base_taggedness) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
MachineType BufferAccess::machine_type() const {
|
||||
switch (external_array_type_) {
|
||||
case kExternalUint8Array:
|
||||
case kExternalUint8ClampedArray:
|
||||
return MachineType::Uint8();
|
||||
case kExternalInt8Array:
|
||||
return MachineType::Int8();
|
||||
case kExternalUint16Array:
|
||||
return MachineType::Uint16();
|
||||
case kExternalInt16Array:
|
||||
return MachineType::Int16();
|
||||
case kExternalUint32Array:
|
||||
return MachineType::Uint32();
|
||||
case kExternalInt32Array:
|
||||
return MachineType::Int32();
|
||||
case kExternalFloat32Array:
|
||||
return MachineType::Float32();
|
||||
case kExternalFloat64Array:
|
||||
return MachineType::Float64();
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
bool operator==(BufferAccess lhs, BufferAccess rhs) {
|
||||
return lhs.external_array_type() == rhs.external_array_type();
|
||||
}
|
||||
|
||||
|
||||
bool operator!=(BufferAccess lhs, BufferAccess rhs) { return !(lhs == rhs); }
|
||||
|
||||
|
||||
size_t hash_value(BufferAccess access) {
|
||||
return base::hash<ExternalArrayType>()(access.external_array_type());
|
||||
}
|
||||
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, BufferAccess access) {
|
||||
switch (access.external_array_type()) {
|
||||
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
|
||||
case kExternal##Type##Array: \
|
||||
return os << #Type;
|
||||
TYPED_ARRAYS(TYPED_ARRAY_CASE)
|
||||
#undef TYPED_ARRAY_CASE
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
BufferAccess const BufferAccessOf(const Operator* op) {
|
||||
DCHECK(op->opcode() == IrOpcode::kLoadBuffer ||
|
||||
op->opcode() == IrOpcode::kStoreBuffer);
|
||||
return OpParameter<BufferAccess>(op);
|
||||
}
|
||||
|
||||
|
||||
bool operator==(FieldAccess const& lhs, FieldAccess const& rhs) {
|
||||
// On purpose we don't include the write barrier kind here, as this method is
|
||||
// really only relevant for eliminating loads and they don't care about the
|
||||
@ -810,28 +753,6 @@ struct SimplifiedOperatorGlobalCache final {
|
||||
kSpeculativeToNumberNumberOperator;
|
||||
SpeculativeToNumberOperator<NumberOperationHint::kNumberOrOddball>
|
||||
kSpeculativeToNumberNumberOrOddballOperator;
|
||||
|
||||
#define BUFFER_ACCESS(Type, type, TYPE, ctype, size) \
|
||||
struct LoadBuffer##Type##Operator final : public Operator1<BufferAccess> { \
|
||||
LoadBuffer##Type##Operator() \
|
||||
: Operator1<BufferAccess>( \
|
||||
IrOpcode::kLoadBuffer, \
|
||||
Operator::kNoDeopt | Operator::kNoThrow | Operator::kNoWrite, \
|
||||
"LoadBuffer", 3, 1, 1, 1, 1, 0, \
|
||||
BufferAccess(kExternal##Type##Array)) {} \
|
||||
}; \
|
||||
struct StoreBuffer##Type##Operator final : public Operator1<BufferAccess> { \
|
||||
StoreBuffer##Type##Operator() \
|
||||
: Operator1<BufferAccess>( \
|
||||
IrOpcode::kStoreBuffer, \
|
||||
Operator::kNoDeopt | Operator::kNoRead | Operator::kNoThrow, \
|
||||
"StoreBuffer", 4, 1, 1, 0, 1, 0, \
|
||||
BufferAccess(kExternal##Type##Array)) {} \
|
||||
}; \
|
||||
LoadBuffer##Type##Operator kLoadBuffer##Type; \
|
||||
StoreBuffer##Type##Operator kStoreBuffer##Type;
|
||||
TYPED_ARRAYS(BUFFER_ACCESS)
|
||||
#undef BUFFER_ACCESS
|
||||
};
|
||||
|
||||
static base::LazyInstance<SimplifiedOperatorGlobalCache>::type
|
||||
@ -1033,30 +954,6 @@ const Operator* SimplifiedOperatorBuilder::Allocate(Type* type,
|
||||
1, 1, 1, 1, 1, 0, AllocateParameters(type, pretenure));
|
||||
}
|
||||
|
||||
|
||||
const Operator* SimplifiedOperatorBuilder::LoadBuffer(BufferAccess access) {
|
||||
switch (access.external_array_type()) {
|
||||
#define LOAD_BUFFER(Type, type, TYPE, ctype, size) \
|
||||
case kExternal##Type##Array: \
|
||||
return &cache_.kLoadBuffer##Type;
|
||||
TYPED_ARRAYS(LOAD_BUFFER)
|
||||
#undef LOAD_BUFFER
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
const Operator* SimplifiedOperatorBuilder::StoreBuffer(BufferAccess access) {
|
||||
switch (access.external_array_type()) {
|
||||
#define STORE_BUFFER(Type, type, TYPE, ctype, size) \
|
||||
case kExternal##Type##Array: \
|
||||
return &cache_.kStoreBuffer##Type;
|
||||
TYPED_ARRAYS(STORE_BUFFER)
|
||||
#undef STORE_BUFFER
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
const Operator* SimplifiedOperatorBuilder::StringFromCodePoint(
|
||||
UnicodeEncoding encoding) {
|
||||
switch (encoding) {
|
||||
|
@ -34,30 +34,6 @@ size_t hash_value(BaseTaggedness);
|
||||
|
||||
std::ostream& operator<<(std::ostream&, BaseTaggedness);
|
||||
|
||||
|
||||
// An access descriptor for loads/stores of array buffers.
|
||||
class BufferAccess final {
|
||||
public:
|
||||
explicit BufferAccess(ExternalArrayType external_array_type)
|
||||
: external_array_type_(external_array_type) {}
|
||||
|
||||
ExternalArrayType external_array_type() const { return external_array_type_; }
|
||||
MachineType machine_type() const;
|
||||
|
||||
private:
|
||||
ExternalArrayType const external_array_type_;
|
||||
};
|
||||
|
||||
V8_EXPORT_PRIVATE bool operator==(BufferAccess, BufferAccess);
|
||||
bool operator!=(BufferAccess, BufferAccess);
|
||||
|
||||
size_t hash_value(BufferAccess);
|
||||
|
||||
V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&, BufferAccess);
|
||||
|
||||
V8_EXPORT_PRIVATE BufferAccess const BufferAccessOf(const Operator* op)
|
||||
WARN_UNUSED_RESULT;
|
||||
|
||||
// An access descriptor for loads/stores of fixed structures like field
|
||||
// accesses of heap objects. Accesses from either tagged or untagged base
|
||||
// pointers are supported; untagging is done automatically during lowering.
|
||||
@ -486,12 +462,6 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
|
||||
const Operator* LoadField(FieldAccess const&);
|
||||
const Operator* StoreField(FieldAccess const&);
|
||||
|
||||
// load-buffer buffer, offset, length
|
||||
const Operator* LoadBuffer(BufferAccess);
|
||||
|
||||
// store-buffer buffer, offset, length, value
|
||||
const Operator* StoreBuffer(BufferAccess);
|
||||
|
||||
// load-element [base + index]
|
||||
const Operator* LoadElement(ElementAccess const&);
|
||||
|
||||
|
@ -1911,18 +1911,6 @@ Type* Typer::Visitor::TypeLoadField(Node* node) {
|
||||
return FieldAccessOf(node->op()).type;
|
||||
}
|
||||
|
||||
Type* Typer::Visitor::TypeLoadBuffer(Node* node) {
|
||||
switch (BufferAccessOf(node->op()).external_array_type()) {
|
||||
#define TYPED_ARRAY_CASE(ElemType, type, TYPE, ctype, size) \
|
||||
case kExternal##ElemType##Array: \
|
||||
return Type::Union(typer_->cache_.k##ElemType, Type::Undefined(), zone());
|
||||
TYPED_ARRAYS(TYPED_ARRAY_CASE)
|
||||
#undef TYPED_ARRAY_CASE
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
Type* Typer::Visitor::TypeLoadElement(Node* node) {
|
||||
return ElementAccessOf(node->op()).type;
|
||||
}
|
||||
@ -1942,12 +1930,6 @@ Type* Typer::Visitor::TypeStoreField(Node* node) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
Type* Typer::Visitor::TypeStoreBuffer(Node* node) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
Type* Typer::Visitor::TypeStoreElement(Node* node) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
@ -1252,8 +1252,6 @@ void Verifier::Visitor::Check(Node* node) {
|
||||
// CheckValueInputIs(node, 0, Type::Object());
|
||||
// CheckTypeIs(node, FieldAccessOf(node->op()).type));
|
||||
break;
|
||||
case IrOpcode::kLoadBuffer:
|
||||
break;
|
||||
case IrOpcode::kLoadElement:
|
||||
// Object -> elementtype
|
||||
// TODO(rossberg): activate once machine ops are typed.
|
||||
@ -1269,8 +1267,6 @@ void Verifier::Visitor::Check(Node* node) {
|
||||
// CheckValueInputIs(node, 1, FieldAccessOf(node->op()).type));
|
||||
CheckNotTyped(node);
|
||||
break;
|
||||
case IrOpcode::kStoreBuffer:
|
||||
break;
|
||||
case IrOpcode::kStoreElement:
|
||||
// (Object, elementtype) -> _|_
|
||||
// TODO(rossberg): activate once machine ops are typed.
|
||||
|
@ -25403,46 +25403,6 @@ TEST(StringConcatOverflow) {
|
||||
}
|
||||
|
||||
|
||||
TEST(TurboAsmDisablesNeuter) {
|
||||
i::FLAG_opt = true;
|
||||
i::FLAG_allow_natives_syntax = true;
|
||||
v8::V8::Initialize();
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
LocalContext context;
|
||||
const char* load =
|
||||
"function Module(stdlib, foreign, heap) {"
|
||||
" 'use asm';"
|
||||
" var MEM32 = new stdlib.Int32Array(heap);"
|
||||
" function load() { return MEM32[0]; }"
|
||||
" return { load: load };"
|
||||
"}"
|
||||
"var buffer = new ArrayBuffer(4);"
|
||||
"var module = Module(this, {}, buffer);"
|
||||
"%OptimizeFunctionOnNextCall(module.load);"
|
||||
"module.load();"
|
||||
"buffer";
|
||||
|
||||
v8::Local<v8::ArrayBuffer> result = CompileRun(load).As<v8::ArrayBuffer>();
|
||||
CHECK(!result->IsNeuterable());
|
||||
|
||||
const char* store =
|
||||
"function Module(stdlib, foreign, heap) {"
|
||||
" 'use asm';"
|
||||
" var MEM32 = new stdlib.Int32Array(heap);"
|
||||
" function store() { MEM32[0] = 0; }"
|
||||
" return { store: store };"
|
||||
"}"
|
||||
"var buffer = new ArrayBuffer(4);"
|
||||
"var module = Module(this, {}, buffer);"
|
||||
"%OptimizeFunctionOnNextCall(module.store);"
|
||||
"module.store();"
|
||||
"buffer";
|
||||
|
||||
result = CompileRun(store).As<v8::ArrayBuffer>();
|
||||
CHECK(!result->IsNeuterable());
|
||||
}
|
||||
|
||||
|
||||
TEST(GetPrototypeAccessControl) {
|
||||
i::FLAG_allow_natives_syntax = true;
|
||||
v8::Isolate* isolate = CcTest::isolate();
|
||||
|
@ -28,19 +28,11 @@ namespace compiler {
|
||||
|
||||
namespace {
|
||||
|
||||
const ExternalArrayType kExternalArrayTypes[] = {
|
||||
kExternalUint8Array, kExternalInt8Array, kExternalUint16Array,
|
||||
kExternalInt16Array, kExternalUint32Array, kExternalInt32Array,
|
||||
kExternalFloat32Array, kExternalFloat64Array};
|
||||
|
||||
const size_t kIndices[] = {0, 1, 42, 100, 1024};
|
||||
|
||||
Type* const kJSTypes[] = {Type::Undefined(), Type::Null(), Type::Boolean(),
|
||||
Type::Number(), Type::String(), Type::Object()};
|
||||
|
||||
STATIC_ASSERT(LANGUAGE_END == 2);
|
||||
const LanguageMode kLanguageModes[] = {SLOPPY, STRICT};
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
@ -449,212 +441,6 @@ TEST_F(JSTypedLoweringTest, JSStoreContext) {
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// JSLoadProperty
|
||||
|
||||
|
||||
TEST_F(JSTypedLoweringTest, JSLoadPropertyFromExternalTypedArray) {
|
||||
const size_t kLength = 17;
|
||||
double backing_store[kLength];
|
||||
Handle<JSArrayBuffer> buffer =
|
||||
NewArrayBuffer(backing_store, sizeof(backing_store));
|
||||
VectorSlotPair feedback;
|
||||
TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) {
|
||||
Handle<JSTypedArray> array =
|
||||
factory()->NewJSTypedArray(type, buffer, 0, kLength);
|
||||
int const element_size = static_cast<int>(array->element_size());
|
||||
|
||||
Node* key = Parameter(
|
||||
Type::Range(kMinInt / element_size, kMaxInt / element_size, zone()));
|
||||
Node* base = HeapConstant(array);
|
||||
Node* context = UndefinedConstant();
|
||||
Node* effect = graph()->start();
|
||||
Node* control = graph()->start();
|
||||
Reduction r =
|
||||
Reduce(graph()->NewNode(javascript()->LoadProperty(feedback), base, key,
|
||||
context, EmptyFrameState(), effect, control));
|
||||
|
||||
Matcher<Node*> offset_matcher =
|
||||
element_size == 1
|
||||
? key
|
||||
: IsNumberShiftLeft(key,
|
||||
IsNumberConstant(WhichPowerOf2(element_size)));
|
||||
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(
|
||||
r.replacement(),
|
||||
IsLoadBuffer(BufferAccess(type),
|
||||
IsPointerConstant(bit_cast<intptr_t>(&backing_store[0])),
|
||||
offset_matcher,
|
||||
IsNumberConstant(array->byte_length()->Number()), effect,
|
||||
control));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_F(JSTypedLoweringTest, JSLoadPropertyFromExternalTypedArrayWithSafeKey) {
|
||||
const size_t kLength = 17;
|
||||
double backing_store[kLength];
|
||||
Handle<JSArrayBuffer> buffer =
|
||||
NewArrayBuffer(backing_store, sizeof(backing_store));
|
||||
VectorSlotPair feedback;
|
||||
TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) {
|
||||
Handle<JSTypedArray> array =
|
||||
factory()->NewJSTypedArray(type, buffer, 0, kLength);
|
||||
ElementAccess access = AccessBuilder::ForTypedArrayElement(type, true);
|
||||
|
||||
int min = random_number_generator()->NextInt(static_cast<int>(kLength));
|
||||
int max = random_number_generator()->NextInt(static_cast<int>(kLength));
|
||||
if (min > max) std::swap(min, max);
|
||||
Node* key = Parameter(Type::Range(min, max, zone()));
|
||||
Node* base = HeapConstant(array);
|
||||
Node* context = UndefinedConstant();
|
||||
Node* effect = graph()->start();
|
||||
Node* control = graph()->start();
|
||||
Reduction r =
|
||||
Reduce(graph()->NewNode(javascript()->LoadProperty(feedback), base, key,
|
||||
context, EmptyFrameState(), effect, control));
|
||||
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(
|
||||
r.replacement(),
|
||||
IsLoadElement(access,
|
||||
IsPointerConstant(bit_cast<intptr_t>(&backing_store[0])),
|
||||
key, effect, control));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// JSStoreProperty
|
||||
|
||||
|
||||
TEST_F(JSTypedLoweringTest, JSStorePropertyToExternalTypedArray) {
|
||||
const size_t kLength = 17;
|
||||
double backing_store[kLength];
|
||||
Handle<JSArrayBuffer> buffer =
|
||||
NewArrayBuffer(backing_store, sizeof(backing_store));
|
||||
TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) {
|
||||
TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
|
||||
Handle<JSTypedArray> array =
|
||||
factory()->NewJSTypedArray(type, buffer, 0, kLength);
|
||||
int const element_size = static_cast<int>(array->element_size());
|
||||
|
||||
Node* key = Parameter(
|
||||
Type::Range(kMinInt / element_size, kMaxInt / element_size, zone()));
|
||||
Node* base = HeapConstant(array);
|
||||
Node* value =
|
||||
Parameter(AccessBuilder::ForTypedArrayElement(type, true).type);
|
||||
Node* context = UndefinedConstant();
|
||||
Node* effect = graph()->start();
|
||||
Node* control = graph()->start();
|
||||
VectorSlotPair feedback;
|
||||
const Operator* op = javascript()->StoreProperty(language_mode, feedback);
|
||||
Node* node = graph()->NewNode(op, base, key, value, context,
|
||||
EmptyFrameState(), effect, control);
|
||||
Reduction r = Reduce(node);
|
||||
|
||||
Matcher<Node*> offset_matcher =
|
||||
element_size == 1
|
||||
? key
|
||||
: IsNumberShiftLeft(
|
||||
key, IsNumberConstant(WhichPowerOf2(element_size)));
|
||||
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(
|
||||
r.replacement(),
|
||||
IsStoreBuffer(
|
||||
BufferAccess(type),
|
||||
IsPointerConstant(bit_cast<intptr_t>(&backing_store[0])),
|
||||
offset_matcher, IsNumberConstant(array->byte_length()->Number()),
|
||||
value, effect, control));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_F(JSTypedLoweringTest, JSStorePropertyToExternalTypedArrayWithConversion) {
|
||||
const size_t kLength = 17;
|
||||
double backing_store[kLength];
|
||||
Handle<JSArrayBuffer> buffer =
|
||||
NewArrayBuffer(backing_store, sizeof(backing_store));
|
||||
TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) {
|
||||
TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
|
||||
Handle<JSTypedArray> array =
|
||||
factory()->NewJSTypedArray(type, buffer, 0, kLength);
|
||||
int const element_size = static_cast<int>(array->element_size());
|
||||
|
||||
Node* key = Parameter(
|
||||
Type::Range(kMinInt / element_size, kMaxInt / element_size, zone()));
|
||||
Node* base = HeapConstant(array);
|
||||
Node* value = Parameter(Type::PlainPrimitive());
|
||||
Node* context = UndefinedConstant();
|
||||
Node* effect = graph()->start();
|
||||
Node* control = graph()->start();
|
||||
VectorSlotPair feedback;
|
||||
const Operator* op = javascript()->StoreProperty(language_mode, feedback);
|
||||
Node* node = graph()->NewNode(op, base, key, value, context,
|
||||
EmptyFrameState(), effect, control);
|
||||
Reduction r = Reduce(node);
|
||||
|
||||
Matcher<Node*> offset_matcher =
|
||||
element_size == 1
|
||||
? key
|
||||
: IsNumberShiftLeft(
|
||||
key, IsNumberConstant(WhichPowerOf2(element_size)));
|
||||
|
||||
Matcher<Node*> value_matcher = IsPlainPrimitiveToNumber(value);
|
||||
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(
|
||||
r.replacement(),
|
||||
IsStoreBuffer(
|
||||
BufferAccess(type),
|
||||
IsPointerConstant(bit_cast<intptr_t>(&backing_store[0])),
|
||||
offset_matcher, IsNumberConstant(array->byte_length()->Number()),
|
||||
value_matcher, effect, control));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_F(JSTypedLoweringTest, JSStorePropertyToExternalTypedArrayWithSafeKey) {
|
||||
const size_t kLength = 17;
|
||||
double backing_store[kLength];
|
||||
Handle<JSArrayBuffer> buffer =
|
||||
NewArrayBuffer(backing_store, sizeof(backing_store));
|
||||
TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) {
|
||||
TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
|
||||
Handle<JSTypedArray> array =
|
||||
factory()->NewJSTypedArray(type, buffer, 0, kLength);
|
||||
ElementAccess access = AccessBuilder::ForTypedArrayElement(type, true);
|
||||
|
||||
int min = random_number_generator()->NextInt(static_cast<int>(kLength));
|
||||
int max = random_number_generator()->NextInt(static_cast<int>(kLength));
|
||||
if (min > max) std::swap(min, max);
|
||||
Node* key = Parameter(Type::Range(min, max, zone()));
|
||||
Node* base = HeapConstant(array);
|
||||
Node* value = Parameter(access.type);
|
||||
Node* context = UndefinedConstant();
|
||||
Node* effect = graph()->start();
|
||||
Node* control = graph()->start();
|
||||
VectorSlotPair feedback;
|
||||
const Operator* op = javascript()->StoreProperty(language_mode, feedback);
|
||||
Node* node = graph()->NewNode(op, base, key, value, context,
|
||||
EmptyFrameState(), effect, control);
|
||||
Reduction r = Reduce(node);
|
||||
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(
|
||||
r.replacement(),
|
||||
IsStoreElement(
|
||||
access, IsPointerConstant(bit_cast<intptr_t>(&backing_store[0])),
|
||||
key, value, effect, control));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// JSLoadNamed
|
||||
|
||||
|
@ -966,132 +966,6 @@ class IsStoreFieldMatcher final : public NodeMatcher {
|
||||
const Matcher<Node*> control_matcher_;
|
||||
};
|
||||
|
||||
|
||||
class IsLoadBufferMatcher final : public NodeMatcher {
|
||||
public:
|
||||
IsLoadBufferMatcher(const Matcher<BufferAccess>& access_matcher,
|
||||
const Matcher<Node*>& buffer_matcher,
|
||||
const Matcher<Node*>& offset_matcher,
|
||||
const Matcher<Node*>& length_matcher,
|
||||
const Matcher<Node*>& effect_matcher,
|
||||
const Matcher<Node*>& control_matcher)
|
||||
: NodeMatcher(IrOpcode::kLoadBuffer),
|
||||
access_matcher_(access_matcher),
|
||||
buffer_matcher_(buffer_matcher),
|
||||
offset_matcher_(offset_matcher),
|
||||
length_matcher_(length_matcher),
|
||||
effect_matcher_(effect_matcher),
|
||||
control_matcher_(control_matcher) {}
|
||||
|
||||
void DescribeTo(std::ostream* os) const final {
|
||||
NodeMatcher::DescribeTo(os);
|
||||
*os << " whose access (";
|
||||
access_matcher_.DescribeTo(os);
|
||||
*os << "), buffer (";
|
||||
buffer_matcher_.DescribeTo(os);
|
||||
*os << "), offset (";
|
||||
offset_matcher_.DescribeTo(os);
|
||||
*os << "), length (";
|
||||
length_matcher_.DescribeTo(os);
|
||||
*os << "), effect (";
|
||||
effect_matcher_.DescribeTo(os);
|
||||
*os << ") and control (";
|
||||
control_matcher_.DescribeTo(os);
|
||||
*os << ")";
|
||||
}
|
||||
|
||||
bool MatchAndExplain(Node* node, MatchResultListener* listener) const final {
|
||||
return (NodeMatcher::MatchAndExplain(node, listener) &&
|
||||
PrintMatchAndExplain(BufferAccessOf(node->op()), "access",
|
||||
access_matcher_, listener) &&
|
||||
PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0),
|
||||
"buffer", buffer_matcher_, listener) &&
|
||||
PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1),
|
||||
"offset", offset_matcher_, listener) &&
|
||||
PrintMatchAndExplain(NodeProperties::GetValueInput(node, 2),
|
||||
"length", length_matcher_, listener) &&
|
||||
PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect",
|
||||
effect_matcher_, listener) &&
|
||||
PrintMatchAndExplain(NodeProperties::GetControlInput(node),
|
||||
"control", control_matcher_, listener));
|
||||
}
|
||||
|
||||
private:
|
||||
const Matcher<BufferAccess> access_matcher_;
|
||||
const Matcher<Node*> buffer_matcher_;
|
||||
const Matcher<Node*> offset_matcher_;
|
||||
const Matcher<Node*> length_matcher_;
|
||||
const Matcher<Node*> effect_matcher_;
|
||||
const Matcher<Node*> control_matcher_;
|
||||
};
|
||||
|
||||
|
||||
class IsStoreBufferMatcher final : public NodeMatcher {
|
||||
public:
|
||||
IsStoreBufferMatcher(const Matcher<BufferAccess>& access_matcher,
|
||||
const Matcher<Node*>& buffer_matcher,
|
||||
const Matcher<Node*>& offset_matcher,
|
||||
const Matcher<Node*>& length_matcher,
|
||||
const Matcher<Node*>& value_matcher,
|
||||
const Matcher<Node*>& effect_matcher,
|
||||
const Matcher<Node*>& control_matcher)
|
||||
: NodeMatcher(IrOpcode::kStoreBuffer),
|
||||
access_matcher_(access_matcher),
|
||||
buffer_matcher_(buffer_matcher),
|
||||
offset_matcher_(offset_matcher),
|
||||
length_matcher_(length_matcher),
|
||||
value_matcher_(value_matcher),
|
||||
effect_matcher_(effect_matcher),
|
||||
control_matcher_(control_matcher) {}
|
||||
|
||||
void DescribeTo(std::ostream* os) const final {
|
||||
NodeMatcher::DescribeTo(os);
|
||||
*os << " whose access (";
|
||||
access_matcher_.DescribeTo(os);
|
||||
*os << "), buffer (";
|
||||
buffer_matcher_.DescribeTo(os);
|
||||
*os << "), offset (";
|
||||
offset_matcher_.DescribeTo(os);
|
||||
*os << "), length (";
|
||||
length_matcher_.DescribeTo(os);
|
||||
*os << "), value (";
|
||||
value_matcher_.DescribeTo(os);
|
||||
*os << "), effect (";
|
||||
effect_matcher_.DescribeTo(os);
|
||||
*os << ") and control (";
|
||||
control_matcher_.DescribeTo(os);
|
||||
*os << ")";
|
||||
}
|
||||
|
||||
bool MatchAndExplain(Node* node, MatchResultListener* listener) const final {
|
||||
return (NodeMatcher::MatchAndExplain(node, listener) &&
|
||||
PrintMatchAndExplain(BufferAccessOf(node->op()), "access",
|
||||
access_matcher_, listener) &&
|
||||
PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0),
|
||||
"buffer", buffer_matcher_, listener) &&
|
||||
PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1),
|
||||
"offset", offset_matcher_, listener) &&
|
||||
PrintMatchAndExplain(NodeProperties::GetValueInput(node, 2),
|
||||
"length", length_matcher_, listener) &&
|
||||
PrintMatchAndExplain(NodeProperties::GetValueInput(node, 3),
|
||||
"value", value_matcher_, listener) &&
|
||||
PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect",
|
||||
effect_matcher_, listener) &&
|
||||
PrintMatchAndExplain(NodeProperties::GetControlInput(node),
|
||||
"control", control_matcher_, listener));
|
||||
}
|
||||
|
||||
private:
|
||||
const Matcher<BufferAccess> access_matcher_;
|
||||
const Matcher<Node*> buffer_matcher_;
|
||||
const Matcher<Node*> offset_matcher_;
|
||||
const Matcher<Node*> length_matcher_;
|
||||
const Matcher<Node*> value_matcher_;
|
||||
const Matcher<Node*> effect_matcher_;
|
||||
const Matcher<Node*> control_matcher_;
|
||||
};
|
||||
|
||||
|
||||
class IsLoadElementMatcher final : public NodeMatcher {
|
||||
public:
|
||||
IsLoadElementMatcher(const Matcher<ElementAccess>& access_matcher,
|
||||
@ -2088,32 +1962,6 @@ Matcher<Node*> IsStoreField(const Matcher<FieldAccess>& access_matcher,
|
||||
control_matcher));
|
||||
}
|
||||
|
||||
|
||||
Matcher<Node*> IsLoadBuffer(const Matcher<BufferAccess>& access_matcher,
|
||||
const Matcher<Node*>& buffer_matcher,
|
||||
const Matcher<Node*>& offset_matcher,
|
||||
const Matcher<Node*>& length_matcher,
|
||||
const Matcher<Node*>& effect_matcher,
|
||||
const Matcher<Node*>& control_matcher) {
|
||||
return MakeMatcher(new IsLoadBufferMatcher(access_matcher, buffer_matcher,
|
||||
offset_matcher, length_matcher,
|
||||
effect_matcher, control_matcher));
|
||||
}
|
||||
|
||||
|
||||
Matcher<Node*> IsStoreBuffer(const Matcher<BufferAccess>& access_matcher,
|
||||
const Matcher<Node*>& buffer_matcher,
|
||||
const Matcher<Node*>& offset_matcher,
|
||||
const Matcher<Node*>& length_matcher,
|
||||
const Matcher<Node*>& value_matcher,
|
||||
const Matcher<Node*>& effect_matcher,
|
||||
const Matcher<Node*>& control_matcher) {
|
||||
return MakeMatcher(new IsStoreBufferMatcher(
|
||||
access_matcher, buffer_matcher, offset_matcher, length_matcher,
|
||||
value_matcher, effect_matcher, control_matcher));
|
||||
}
|
||||
|
||||
|
||||
Matcher<Node*> IsLoadElement(const Matcher<ElementAccess>& access_matcher,
|
||||
const Matcher<Node*>& base_matcher,
|
||||
const Matcher<Node*>& index_matcher,
|
||||
|
@ -122,81 +122,6 @@ INSTANTIATE_TEST_CASE_P(SimplifiedOperatorTest, SimplifiedPureOperatorTest,
|
||||
::testing::ValuesIn(kPureOperators));
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Buffer access operators.
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
const ExternalArrayType kExternalArrayTypes[] = {
|
||||
kExternalUint8Array, kExternalInt8Array, kExternalUint16Array,
|
||||
kExternalInt16Array, kExternalUint32Array, kExternalInt32Array,
|
||||
kExternalFloat32Array, kExternalFloat64Array};
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
class SimplifiedBufferAccessOperatorTest
|
||||
: public TestWithZone,
|
||||
public ::testing::WithParamInterface<ExternalArrayType> {};
|
||||
|
||||
|
||||
TEST_P(SimplifiedBufferAccessOperatorTest, InstancesAreGloballyShared) {
|
||||
BufferAccess const access(GetParam());
|
||||
SimplifiedOperatorBuilder simplified1(zone());
|
||||
SimplifiedOperatorBuilder simplified2(zone());
|
||||
EXPECT_EQ(simplified1.LoadBuffer(access), simplified2.LoadBuffer(access));
|
||||
EXPECT_EQ(simplified1.StoreBuffer(access), simplified2.StoreBuffer(access));
|
||||
}
|
||||
|
||||
|
||||
TEST_P(SimplifiedBufferAccessOperatorTest, LoadBuffer) {
|
||||
SimplifiedOperatorBuilder simplified(zone());
|
||||
BufferAccess const access(GetParam());
|
||||
const Operator* op = simplified.LoadBuffer(access);
|
||||
|
||||
EXPECT_EQ(IrOpcode::kLoadBuffer, op->opcode());
|
||||
EXPECT_EQ(Operator::kNoDeopt | Operator::kNoThrow | Operator::kNoWrite,
|
||||
op->properties());
|
||||
EXPECT_EQ(access, BufferAccessOf(op));
|
||||
|
||||
EXPECT_EQ(3, op->ValueInputCount());
|
||||
EXPECT_EQ(1, op->EffectInputCount());
|
||||
EXPECT_EQ(1, op->ControlInputCount());
|
||||
EXPECT_EQ(5, OperatorProperties::GetTotalInputCount(op));
|
||||
|
||||
EXPECT_EQ(1, op->ValueOutputCount());
|
||||
EXPECT_EQ(1, op->EffectOutputCount());
|
||||
EXPECT_EQ(0, op->ControlOutputCount());
|
||||
}
|
||||
|
||||
|
||||
TEST_P(SimplifiedBufferAccessOperatorTest, StoreBuffer) {
|
||||
SimplifiedOperatorBuilder simplified(zone());
|
||||
BufferAccess const access(GetParam());
|
||||
const Operator* op = simplified.StoreBuffer(access);
|
||||
|
||||
EXPECT_EQ(IrOpcode::kStoreBuffer, op->opcode());
|
||||
EXPECT_EQ(Operator::kNoDeopt | Operator::kNoRead | Operator::kNoThrow,
|
||||
op->properties());
|
||||
EXPECT_EQ(access, BufferAccessOf(op));
|
||||
|
||||
EXPECT_EQ(4, op->ValueInputCount());
|
||||
EXPECT_EQ(1, op->EffectInputCount());
|
||||
EXPECT_EQ(1, op->ControlInputCount());
|
||||
EXPECT_EQ(6, OperatorProperties::GetTotalInputCount(op));
|
||||
|
||||
EXPECT_EQ(0, op->ValueOutputCount());
|
||||
EXPECT_EQ(1, op->EffectOutputCount());
|
||||
EXPECT_EQ(0, op->ControlOutputCount());
|
||||
}
|
||||
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(SimplifiedOperatorTest,
|
||||
SimplifiedBufferAccessOperatorTest,
|
||||
::testing::ValuesIn(kExternalArrayTypes));
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Element access operators.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user