| Index: src/hydrogen.cc
|
| diff --git a/src/hydrogen.cc b/src/hydrogen.cc
|
| index 634acd7f39dc54082e9e631e378a8ff3de0b6deb..accad940c56c7de00842853510ff65208dff7b88 100644
|
| --- a/src/hydrogen.cc
|
| +++ b/src/hydrogen.cc
|
| @@ -5403,7 +5403,9 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupInPrototypes() {
|
|
|
|
|
| bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadMonomorphic() {
|
| - if (!CanInlinePropertyAccess(*map_)) return IsStringLength();
|
| + if (!CanInlinePropertyAccess(*map_)) {
|
| + return IsStringLength() || IsFloat32x4OrInt32x4PropertyCallback();
|
| + }
|
| if (IsJSObjectFieldAccessor()) return true;
|
| if (!LookupDescriptor()) return false;
|
| if (lookup_.IsFound()) return true;
|
| @@ -5424,6 +5426,15 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadAsMonomorphic(
|
| return true;
|
| }
|
|
|
| + if (IsFloat32x4OrInt32x4PropertyCallback()) {
|
| + for (int i = 1; i < types->length(); ++i) {
|
| + if (types->at(i)->instance_type() == types->first()->instance_type()) {
|
| + return false;
|
| + }
|
| + }
|
| + return true;
|
| + }
|
| +
|
| if (IsArrayLength()) {
|
| bool is_fast = IsFastElementsKind(map_->elements_kind());
|
| for (int i = 1; i < types->length(); ++i) {
|
| @@ -5453,6 +5464,65 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadAsMonomorphic(
|
| }
|
|
|
|
|
| +static BuiltinFunctionId NameToId(Isolate* isolate, Handle<String> name,
|
| + InstanceType type) {
|
| + BuiltinFunctionId id;
|
| + if (name->Equals(isolate->heap()->signMask())) {
|
| + id = type == FLOAT32x4_TYPE ? kFloat32x4SignMask : kInt32x4SignMask;
|
| + } else if (name->Equals(isolate->heap()->x())) {
|
| + id = type == FLOAT32x4_TYPE ? kFloat32x4X : kInt32x4X;
|
| + } else if (name->Equals(isolate->heap()->y())) {
|
| + id = type == FLOAT32x4_TYPE ? kFloat32x4Y : kInt32x4Y;
|
| + } else if (name->Equals(isolate->heap()->z())) {
|
| + id = type == FLOAT32x4_TYPE ? kFloat32x4Z : kInt32x4Z;
|
| + } else if (name->Equals(isolate->heap()->w())) {
|
| + id = type == FLOAT32x4_TYPE ? kFloat32x4W : kInt32x4W;
|
| + } else if (name->Equals(isolate->heap()->flagX())) {
|
| + ASSERT(type == INT32x4_TYPE);
|
| + id = kInt32x4FlagX;
|
| + } else if (name->Equals(isolate->heap()->flagY())) {
|
| + ASSERT(type == INT32x4_TYPE);
|
| + id = kInt32x4FlagY;
|
| + } else if (name->Equals(isolate->heap()->flagZ())) {
|
| + ASSERT(type == INT32x4_TYPE);
|
| + id = kInt32x4FlagZ;
|
| + } else if (name->Equals(isolate->heap()->flagW())) {
|
| + ASSERT(type == INT32x4_TYPE);
|
| + id = kInt32x4FlagW;
|
| + } else {
|
| + UNREACHABLE();
|
| + id = kFloat32x4OrInt32x4Unreachable;
|
| + }
|
| +
|
| + return id;
|
| +}
|
| +
|
| +
|
| +static bool IsSIMDProperty(Handle<String> name, uint8_t* mask) {
|
| + SmartArrayPointer<char> cstring = name->ToCString();
|
| + int i = 0;
|
| + while (i <= 3) {
|
| + int shift = 0;
|
| + switch (cstring[i]) {
|
| + case 'W':
|
| + shift++;
|
| + case 'Z':
|
| + shift++;
|
| + case 'Y':
|
| + shift++;
|
| + case 'X':
|
| + break;
|
| + default:
|
| + return false;
|
| + }
|
| + *mask |= (shift << 2*i);
|
| + i++;
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| +
|
| HInstruction* HOptimizedGraphBuilder::BuildLoadMonomorphic(
|
| PropertyAccessInfo* info,
|
| HValue* object,
|
| @@ -5475,6 +5545,18 @@ HInstruction* HOptimizedGraphBuilder::BuildLoadMonomorphic(
|
| if (!info->lookup()->IsFound()) return graph()->GetConstantUndefined();
|
|
|
| if (info->lookup()->IsField()) {
|
| + if (info->map()->constructor()->IsJSFunction()) {
|
| + JSFunction* constructor = JSFunction::cast(info->map()->constructor());
|
| + String* class_name =
|
| + String::cast(constructor->shared()->instance_class_name());
|
| + uint8_t mask = 0;
|
| + if (class_name->Equals(isolate()->heap()->simd()) &&
|
| + IsSIMDProperty(info->name(), &mask) &&
|
| + CpuFeatures::IsSupported(SSE2)) {
|
| + return New<HConstant>(mask);
|
| + }
|
| + }
|
| +
|
| return BuildLoadNamedField(checked_holder, info->access());
|
| }
|
|
|
| @@ -6582,6 +6664,24 @@ static bool AreStringTypes(SmallMapList* types) {
|
| }
|
|
|
|
|
| +static bool AreInt32x4Types(SmallMapList* types) {
|
| + if (types == NULL || types->length() == 0) return false;
|
| + for (int i = 0; i < types->length(); i++) {
|
| + if (types->at(i)->instance_type() != INT32x4_TYPE) return false;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +
|
| +static bool AreFloat32x4Types(SmallMapList* types) {
|
| + if (types == NULL || types->length() == 0) return false;
|
| + for (int i = 0; i < types->length(); i++) {
|
| + if (types->at(i)->instance_type() != FLOAT32x4_TYPE) return false;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +
|
| void HOptimizedGraphBuilder::BuildLoad(Property* expr,
|
| BailoutId ast_id) {
|
| HInstruction* instr = NULL;
|
| @@ -6612,16 +6712,44 @@ void HOptimizedGraphBuilder::BuildLoad(Property* expr,
|
| ast_id, expr->LoadId(), object, types, name);
|
| }
|
|
|
| - BuildCheckHeapObject(object);
|
| - HInstruction* checked_object;
|
| if (AreStringTypes(types)) {
|
| - checked_object =
|
| + BuildCheckHeapObject(object);
|
| + HInstruction* checked_object =
|
| Add<HCheckInstanceType>(object, HCheckInstanceType::IS_STRING);
|
| + instr = BuildLoadMonomorphic(
|
| + &info, object, checked_object, ast_id, expr->LoadId());
|
| + } else if (AreFloat32x4Types(types) && CpuFeatures::IsSupported(SSE2)) {
|
| + Handle<JSFunction> function(
|
| + isolate()->native_context()->float32x4_function());
|
| + HInstruction* constant_function = Add<HConstant>(function);
|
| + HObjectAccess map_access = HObjectAccess::ForPrototypeOrInitialMap();
|
| + HInstruction* map = Add<HLoadNamedField>(constant_function, map_access);
|
| + HObjectAccess prototype_access = HObjectAccess::ForMapPrototype();
|
| + HInstruction* prototype = Add<HLoadNamedField>(map, prototype_access);
|
| + Handle<Map> initial_function_prototype_map(
|
| + isolate()->native_context()->float32x4_function_prototype_map());
|
| + BuildCheckMap(prototype, initial_function_prototype_map);
|
| + BuiltinFunctionId id = NameToId(isolate(), name, FLOAT32x4_TYPE);
|
| + instr = NewUncasted<HUnarySIMDOperation>(object, id);
|
| + } else if (AreInt32x4Types(types) && CpuFeatures::IsSupported(SSE2)) {
|
| + Handle<JSFunction> function(
|
| + isolate()->native_context()->int32x4_function());
|
| + HInstruction* constant_function = Add<HConstant>(function);
|
| + HObjectAccess map_access = HObjectAccess::ForPrototypeOrInitialMap();
|
| + HInstruction* map = Add<HLoadNamedField>(constant_function, map_access);
|
| + HObjectAccess prototype_access = HObjectAccess::ForMapPrototype();
|
| + HInstruction* prototype = Add<HLoadNamedField>(map, prototype_access);
|
| + Handle<Map> initial_function_prototype_map(
|
| + isolate()->native_context()->int32x4_function_prototype_map());
|
| + BuildCheckMap(prototype, initial_function_prototype_map);
|
| + BuiltinFunctionId id = NameToId(isolate(), name, INT32x4_TYPE);
|
| + instr = NewUncasted<HUnarySIMDOperation>(object, id);
|
| } else {
|
| - checked_object = Add<HCheckMaps>(object, types);
|
| + BuildCheckHeapObject(object);
|
| + HInstruction* checked_object = Add<HCheckMaps>(object, types);
|
| + instr = BuildLoadMonomorphic(
|
| + &info, object, checked_object, ast_id, expr->LoadId());
|
| }
|
| - instr = BuildLoadMonomorphic(
|
| - &info, object, checked_object, ast_id, expr->LoadId());
|
| if (instr == NULL) return;
|
| if (instr->IsLinked()) return ast_context()->ReturnValue(instr);
|
| } else {
|
| @@ -7383,6 +7511,115 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr,
|
| return true;
|
| }
|
| break;
|
| + case kFloat32x4Zero:
|
| + if (expr->arguments()->length() == 0) {
|
| + if (!CpuFeatures::IsSupported(SSE2)) return false;
|
| + Drop(1); // Receiver.
|
| + HInstruction* op = NewUncasted<HNullarySIMDOperation>(id);
|
| + if (drop_extra) Drop(1); // Optionally drop the function.
|
| + ast_context()->ReturnInstruction(op, expr->id());
|
| + return true;
|
| + }
|
| + break;
|
| + case kSIMDAbs:
|
| + case kSIMDNeg:
|
| + case kSIMDNegU32:
|
| + case kSIMDReciprocal:
|
| + case kSIMDReciprocalSqrt:
|
| + case kSIMDSqrt:
|
| + case kSIMDBitsToFloat32x4:
|
| + case kSIMDToFloat32x4:
|
| + case kSIMDBitsToInt32x4:
|
| + case kSIMDToInt32x4:
|
| + case kFloat32x4Splat:
|
| + case kInt32x4Splat:
|
| + if (expr->arguments()->length() == 1) {
|
| + if (!CpuFeatures::IsSupported(SSE2)) return false;
|
| + HValue* argument = Pop();
|
| + Drop(1); // Receiver.
|
| + HInstruction* op = NewUncasted<HUnarySIMDOperation>(argument, id);
|
| + if (drop_extra) Drop(1); // Optionally drop the function.
|
| + ast_context()->ReturnInstruction(op, expr->id());
|
| + return true;
|
| + }
|
| + break;
|
| + case kSIMDAdd:
|
| + case kSIMDSub:
|
| + case kSIMDMul:
|
| + case kSIMDDiv:
|
| + case kSIMDMin:
|
| + case kSIMDMax:
|
| + case kSIMDScale:
|
| + case kSIMDAnd:
|
| + case kSIMDOr:
|
| + case kSIMDXor:
|
| + case kSIMDAddU32:
|
| + case kSIMDSubU32:
|
| + case kSIMDMulU32:
|
| + case kSIMDShuffle:
|
| + case kSIMDShuffleU32:
|
| + case kSIMDLessThan:
|
| + case kSIMDLessThanOrEqual:
|
| + case kSIMDEqual:
|
| + case kSIMDNotEqual:
|
| + case kSIMDGreaterThanOrEqual:
|
| + case kSIMDGreaterThan:
|
| + case kSIMDWithX:
|
| + case kSIMDWithY:
|
| + case kSIMDWithZ:
|
| + case kSIMDWithW:
|
| + case kSIMDWithXu32:
|
| + case kSIMDWithYu32:
|
| + case kSIMDWithZu32:
|
| + case kSIMDWithWu32:
|
| + case kSIMDWithFlagX:
|
| + case kSIMDWithFlagY:
|
| + case kSIMDWithFlagZ:
|
| + case kSIMDWithFlagW:
|
| + if (expr->arguments()->length() == 2) {
|
| + if (!CpuFeatures::IsSupported(SSE2)) return false;
|
| + HValue* right = Pop();
|
| + HValue* left = Pop();
|
| + Drop(1); // Receiver.
|
| + HInstruction* op = NewUncasted<HBinarySIMDOperation>(left, right, id);
|
| + if (drop_extra) Drop(1); // Optionally drop the function.
|
| + ast_context()->ReturnInstruction(op, expr->id());
|
| + return true;
|
| + }
|
| + break;
|
| + case kSIMDSelect:
|
| + case kSIMDShuffleMix:
|
| + case kSIMDClamp:
|
| + if (expr->arguments()->length() == 3) {
|
| + if (!CpuFeatures::IsSupported(SSE2)) return false;
|
| + HValue* right = Pop();
|
| + HValue* left = Pop();
|
| + HValue* value = Pop();
|
| + Drop(1); // Receiver.
|
| + HInstruction* op =
|
| + NewUncasted<HTernarySIMDOperation>(value, left, right, id);
|
| + if (drop_extra) Drop(1); // Optionally drop the function.
|
| + ast_context()->ReturnInstruction(op, expr->id());
|
| + return true;
|
| + }
|
| + break;
|
| + case kFloat32x4Constructor:
|
| + case kInt32x4Constructor:
|
| + case kInt32x4Bool:
|
| + if (expr->arguments()->length() == 4) {
|
| + if (!CpuFeatures::IsSupported(SSE2)) return false;
|
| + HValue* w = Pop();
|
| + HValue* z = Pop();
|
| + HValue* y = Pop();
|
| + HValue* x = Pop();
|
| + Drop(1); // Receiver.
|
| + HInstruction* op =
|
| + NewUncasted<HQuarternarySIMDOperation>(x, y, z, w, id);
|
| + if (drop_extra) Drop(1); // Optionally drop the function.
|
| + ast_context()->ReturnInstruction(op, expr->id());
|
| + return true;
|
| + }
|
| + break;
|
| default:
|
| // Not supported for inlining yet.
|
| break;
|
| @@ -7507,6 +7744,158 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
|
| return true;
|
| }
|
| break;
|
| + case kFloat32x4Zero:
|
| + if (argument_count == 1 && check_type == RECEIVER_MAP_CHECK) {
|
| + if (!CpuFeatures::IsSupported(SSE2)) return false;
|
| + AddCheckConstantFunction(expr->holder(), receiver, receiver_map);
|
| + Drop(1); // Receiver.
|
| + HInstruction* op = NewUncasted<HNullarySIMDOperation>(id);
|
| + ast_context()->ReturnInstruction(op, expr->id());
|
| + return true;
|
| + }
|
| + break;
|
| + case kSIMDAbs:
|
| + case kSIMDNeg:
|
| + case kSIMDNegU32:
|
| + case kSIMDReciprocal:
|
| + case kSIMDReciprocalSqrt:
|
| + case kSIMDSqrt:
|
| + case kSIMDBitsToFloat32x4:
|
| + case kSIMDToFloat32x4:
|
| + case kSIMDBitsToInt32x4:
|
| + case kSIMDToInt32x4:
|
| + case kFloat32x4Splat:
|
| + case kInt32x4Splat:
|
| + if (argument_count == 2 && check_type == RECEIVER_MAP_CHECK) {
|
| + if (!CpuFeatures::IsSupported(SSE2)) return false;
|
| + AddCheckConstantFunction(expr->holder(), receiver, receiver_map);
|
| + HValue* argument = Pop();
|
| + Drop(1); // Receiver.
|
| + HInstruction* op = NewUncasted<HUnarySIMDOperation>(argument, id);
|
| + ast_context()->ReturnInstruction(op, expr->id());
|
| + return true;
|
| + }
|
| + break;
|
| + case kSIMDAdd:
|
| + case kSIMDSub:
|
| + case kSIMDMul:
|
| + case kSIMDDiv:
|
| + case kSIMDMin:
|
| + case kSIMDMax:
|
| + case kSIMDScale:
|
| + case kSIMDAnd:
|
| + case kSIMDOr:
|
| + case kSIMDXor:
|
| + case kSIMDAddU32:
|
| + case kSIMDSubU32:
|
| + case kSIMDMulU32:
|
| + case kSIMDShuffle:
|
| + case kSIMDShuffleU32:
|
| + case kSIMDLessThan:
|
| + case kSIMDLessThanOrEqual:
|
| + case kSIMDEqual:
|
| + case kSIMDNotEqual:
|
| + case kSIMDGreaterThanOrEqual:
|
| + case kSIMDGreaterThan:
|
| + case kSIMDWithX:
|
| + case kSIMDWithY:
|
| + case kSIMDWithZ:
|
| + case kSIMDWithW:
|
| + case kSIMDWithXu32:
|
| + case kSIMDWithYu32:
|
| + case kSIMDWithZu32:
|
| + case kSIMDWithWu32:
|
| + case kSIMDWithFlagX:
|
| + case kSIMDWithFlagY:
|
| + case kSIMDWithFlagZ:
|
| + case kSIMDWithFlagW:
|
| + if (argument_count == 3 && check_type == RECEIVER_MAP_CHECK) {
|
| + if (!CpuFeatures::IsSupported(SSE2)) return false;
|
| + AddCheckConstantFunction(expr->holder(), receiver, receiver_map);
|
| + HValue* right = Pop();
|
| + HValue* left = Pop();
|
| + Drop(1); // Receiver.
|
| + HInstruction* op = NewUncasted<HBinarySIMDOperation>(left, right, id);
|
| + ast_context()->ReturnInstruction(op, expr->id());
|
| + return true;
|
| + }
|
| + break;
|
| + case kSIMDSelect:
|
| + case kSIMDShuffleMix:
|
| + case kSIMDClamp:
|
| + if (argument_count == 4 && check_type == RECEIVER_MAP_CHECK) {
|
| + if (!CpuFeatures::IsSupported(SSE2)) return false;
|
| + AddCheckConstantFunction(expr->holder(), receiver, receiver_map);
|
| + HValue* right = Pop();
|
| + HValue* left = Pop();
|
| + HValue* value = Pop();
|
| + Drop(1); // Receiver.
|
| + HInstruction* op =
|
| + NewUncasted<HTernarySIMDOperation>(value, left, right, id);
|
| + ast_context()->ReturnInstruction(op, expr->id());
|
| + return true;
|
| + }
|
| + break;
|
| + case kInt32x4Bool:
|
| + if (argument_count == 5 && check_type == RECEIVER_MAP_CHECK) {
|
| + if (!CpuFeatures::IsSupported(SSE2)) return false;
|
| + AddCheckConstantFunction(expr->holder(), receiver, receiver_map);
|
| + HValue* w = Pop();
|
| + HValue* z = Pop();
|
| + HValue* y = Pop();
|
| + HValue* x = Pop();
|
| + Drop(1); // Receiver.
|
| + HValue* context = environment()->context();
|
| + HInstruction* op =
|
| + HQuarternarySIMDOperation::New(zone(), context, x, y, z, w, id);
|
| + op->set_position(expr->position());
|
| + ast_context()->ReturnInstruction(op, expr->id());
|
| + return true;
|
| + }
|
| + break;
|
| + case kFloat32x4ArrayGetAt:
|
| + case kInt32x4ArrayGetAt:
|
| + if (argument_count == 2 && check_type == RECEIVER_MAP_CHECK) {
|
| + if (!CpuFeatures::IsSupported(SSE2)) return false;
|
| + AddCheckConstantFunction(expr->holder(), receiver, receiver_map);
|
| + HValue* key = Pop();
|
| + HValue* typed32x4_array = Pop();
|
| + ASSERT(typed32x4_array == receiver);
|
| + HInstruction* instr = BuildUncheckedMonomorphicElementAccess(
|
| + typed32x4_array, key, NULL,
|
| + receiver_map->instance_type() == JS_ARRAY_TYPE,
|
| + receiver_map->elements_kind(),
|
| + false, // is_store.
|
| + NEVER_RETURN_HOLE, // load_mode.
|
| + STANDARD_STORE);
|
| + ast_context()->ReturnValue(instr);
|
| + return true;
|
| + }
|
| + break;
|
| + case kFloat32x4ArraySetAt:
|
| + case kInt32x4ArraySetAt:
|
| + if (argument_count == 3 && check_type == RECEIVER_MAP_CHECK) {
|
| + if (!CpuFeatures::IsSupported(SSE2)) return false;
|
| + AddCheckConstantFunction(expr->holder(), receiver, receiver_map);
|
| + HValue* value = Pop();
|
| + HValue* key = Pop();
|
| + HValue* typed32x4_array = Pop();
|
| + ASSERT(typed32x4_array == receiver);
|
| + // TODO(haitao): add STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS.
|
| + KeyedAccessStoreMode store_mode = STANDARD_STORE;
|
| + BuildUncheckedMonomorphicElementAccess(
|
| + typed32x4_array, key, value,
|
| + receiver_map->instance_type() == JS_ARRAY_TYPE,
|
| + receiver_map->elements_kind(),
|
| + true, // is_store.
|
| + NEVER_RETURN_HOLE, // load_mode.
|
| + store_mode);
|
| + Push(value);
|
| + Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE);
|
| + ast_context()->ReturnValue(Pop());
|
| + return true;
|
| + }
|
| + break;
|
| default:
|
| // Not yet supported for inlining.
|
| break;
|
| @@ -10655,6 +11044,12 @@ void HTracer::TraceLiveRange(LiveRange* range, const char* type,
|
| if (op->IsDoubleRegister()) {
|
| trace_.Add(" \"%s\"",
|
| DoubleRegister::AllocationIndexToString(assigned_reg));
|
| + } else if (op->IsFloat32x4Register()) {
|
| + trace_.Add(" \"%s\"",
|
| + Float32x4Register::AllocationIndexToString(assigned_reg));
|
| + } else if (op->IsInt32x4Register()) {
|
| + trace_.Add(" \"%s\"",
|
| + Int32x4Register::AllocationIndexToString(assigned_reg));
|
| } else {
|
| ASSERT(op->IsRegister());
|
| trace_.Add(" \"%s\"", Register::AllocationIndexToString(assigned_reg));
|
| @@ -10663,6 +11058,10 @@ void HTracer::TraceLiveRange(LiveRange* range, const char* type,
|
| LOperand* op = range->TopLevel()->GetSpillOperand();
|
| if (op->IsDoubleStackSlot()) {
|
| trace_.Add(" \"double_stack:%d\"", op->index());
|
| + } else if (op->IsFloat32x4StackSlot()) {
|
| + trace_.Add(" \"float32x4_stack:%d\"", op->index());
|
| + } else if (op->IsInt32x4StackSlot()) {
|
| + trace_.Add(" \"int32x4_stack:%d\"", op->index());
|
| } else {
|
| ASSERT(op->IsStackSlot());
|
| trace_.Add(" \"stack:%d\"", op->index());
|
|
|