| Index: runtime/vm/flow_graph_optimizer.cc
|
| diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
|
| index e92721a45d743d3f5429e02922286ca778c44fb7..5ff17358784cc36a4ca298e59a8007eb87b4d650 100644
|
| --- a/runtime/vm/flow_graph_optimizer.cc
|
| +++ b/runtime/vm/flow_graph_optimizer.cc
|
| @@ -4497,134 +4497,157 @@ void FlowGraphOptimizer::VisitStaticCall(StaticCallInstr* call) {
|
| if (unary_kind != MathUnaryInstr::kIllegal) {
|
| if (FLAG_precompilation) {
|
| // TODO(srdjan): Adapt MathUnaryInstr to allow tagged inputs as well.
|
| - } else {
|
| - MathUnaryInstr* math_unary =
|
| - new(Z) MathUnaryInstr(unary_kind,
|
| - new(Z) Value(call->ArgumentAt(0)),
|
| - call->deopt_id());
|
| - ReplaceCall(call, math_unary);
|
| - }
|
| - } else if ((recognized_kind == MethodRecognizer::kFloat32x4Zero) ||
|
| - (recognized_kind == MethodRecognizer::kFloat32x4Splat) ||
|
| - (recognized_kind == MethodRecognizer::kFloat32x4Constructor) ||
|
| - (recognized_kind == MethodRecognizer::kFloat32x4FromFloat64x2)) {
|
| - TryInlineFloat32x4Constructor(call, recognized_kind);
|
| - } else if ((recognized_kind == MethodRecognizer::kFloat64x2Constructor) ||
|
| - (recognized_kind == MethodRecognizer::kFloat64x2Zero) ||
|
| - (recognized_kind == MethodRecognizer::kFloat64x2Splat) ||
|
| - (recognized_kind == MethodRecognizer::kFloat64x2FromFloat32x4)) {
|
| - TryInlineFloat64x2Constructor(call, recognized_kind);
|
| - } else if ((recognized_kind == MethodRecognizer::kInt32x4BoolConstructor) ||
|
| - (recognized_kind == MethodRecognizer::kInt32x4Constructor)) {
|
| - TryInlineInt32x4Constructor(call, recognized_kind);
|
| - } else if (recognized_kind == MethodRecognizer::kObjectConstructor) {
|
| - // Remove the original push arguments.
|
| - for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
|
| - PushArgumentInstr* push = call->PushArgumentAt(i);
|
| - push->ReplaceUsesWith(push->value()->definition());
|
| - push->RemoveFromGraph();
|
| - }
|
| - // Manually replace call with global null constant. ReplaceCall can't
|
| - // be used for definitions that are already in the graph.
|
| - call->ReplaceUsesWith(flow_graph_->constant_null());
|
| - ASSERT(current_iterator()->Current() == call);
|
| - current_iterator()->RemoveCurrentFromGraph();;
|
| - } else if ((recognized_kind == MethodRecognizer::kMathMin) ||
|
| - (recognized_kind == MethodRecognizer::kMathMax)) {
|
| - // We can handle only monomorphic min/max call sites with both arguments
|
| - // being either doubles or smis.
|
| - if (call->HasICData() && (call->ic_data()->NumberOfChecks() == 1)) {
|
| - const ICData& ic_data = *call->ic_data();
|
| - intptr_t result_cid = kIllegalCid;
|
| - if (ICDataHasReceiverArgumentClassIds(ic_data, kDoubleCid, kDoubleCid)) {
|
| - result_cid = kDoubleCid;
|
| - } else if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) {
|
| - result_cid = kSmiCid;
|
| - }
|
| - if (result_cid != kIllegalCid) {
|
| - MathMinMaxInstr* min_max = new(Z) MathMinMaxInstr(
|
| - recognized_kind,
|
| - new(Z) Value(call->ArgumentAt(0)),
|
| - new(Z) Value(call->ArgumentAt(1)),
|
| - call->deopt_id(),
|
| - result_cid);
|
| - const ICData& unary_checks =
|
| - ICData::ZoneHandle(Z, ic_data.AsUnaryClassChecks());
|
| - AddCheckClass(min_max->left()->definition(),
|
| - unary_checks,
|
| - call->deopt_id(),
|
| - call->env(),
|
| - call);
|
| - AddCheckClass(min_max->right()->definition(),
|
| - unary_checks,
|
| - call->deopt_id(),
|
| - call->env(),
|
| - call);
|
| - ReplaceCall(call, min_max);
|
| - }
|
| - }
|
| - } else if ((recognized_kind == MethodRecognizer::kMathDoublePow) ||
|
| - (recognized_kind == MethodRecognizer::kMathAtan) ||
|
| - (recognized_kind == MethodRecognizer::kMathAtan2)) {
|
| - if (FLAG_precompilation) {
|
| - // No UnboxDouble instructons allowed.
|
| return;
|
| }
|
| - // InvokeMathCFunctionInstr requires unboxed doubles. UnboxDouble
|
| - // instructions contain type checks and conversions to double.
|
| - ZoneGrowableArray<Value*>* args =
|
| - new(Z) ZoneGrowableArray<Value*>(call->ArgumentCount());
|
| - for (intptr_t i = 0; i < call->ArgumentCount(); i++) {
|
| - args->Add(new(Z) Value(call->ArgumentAt(i)));
|
| - }
|
| - InvokeMathCFunctionInstr* invoke =
|
| - new(Z) InvokeMathCFunctionInstr(args,
|
| - call->deopt_id(),
|
| - recognized_kind,
|
| - call->token_pos());
|
| - ReplaceCall(call, invoke);
|
| - } else if (recognized_kind == MethodRecognizer::kDoubleFromInteger) {
|
| - if (call->HasICData() && (call->ic_data()->NumberOfChecks() == 1)) {
|
| - const ICData& ic_data = *call->ic_data();
|
| - if (CanUnboxDouble()) {
|
| - if (ArgIsAlways(kSmiCid, ic_data, 1)) {
|
| - Definition* arg = call->ArgumentAt(1);
|
| - AddCheckSmi(arg, call->deopt_id(), call->env(), call);
|
| - ReplaceCall(call,
|
| - new(Z) SmiToDoubleInstr(new(Z) Value(arg),
|
| - call->token_pos()));
|
| - } else if (ArgIsAlways(kMintCid, ic_data, 1) &&
|
| - CanConvertUnboxedMintToDouble()) {
|
| - Definition* arg = call->ArgumentAt(1);
|
| - ReplaceCall(call,
|
| - new(Z) MintToDoubleInstr(new(Z) Value(arg),
|
| - call->deopt_id()));
|
| + MathUnaryInstr* math_unary =
|
| + new(Z) MathUnaryInstr(unary_kind,
|
| + new(Z) Value(call->ArgumentAt(0)),
|
| + call->deopt_id());
|
| + ReplaceCall(call, math_unary);
|
| + return;
|
| + }
|
| + switch (recognized_kind) {
|
| + case MethodRecognizer::kFloat32x4Zero:
|
| + case MethodRecognizer::kFloat32x4Splat:
|
| + case MethodRecognizer::kFloat32x4Constructor:
|
| + case MethodRecognizer::kFloat32x4FromFloat64x2:
|
| + TryInlineFloat32x4Constructor(call, recognized_kind);
|
| + break;
|
| + case MethodRecognizer::kFloat64x2Constructor:
|
| + case MethodRecognizer::kFloat64x2Zero:
|
| + case MethodRecognizer::kFloat64x2Splat:
|
| + case MethodRecognizer::kFloat64x2FromFloat32x4:
|
| + TryInlineFloat64x2Constructor(call, recognized_kind);
|
| + break;
|
| + case MethodRecognizer::kInt32x4BoolConstructor:
|
| + case MethodRecognizer::kInt32x4Constructor:
|
| + TryInlineInt32x4Constructor(call, recognized_kind);
|
| + break;
|
| + case MethodRecognizer::kObjectConstructor: {
|
| + // Remove the original push arguments.
|
| + for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
|
| + PushArgumentInstr* push = call->PushArgumentAt(i);
|
| + push->ReplaceUsesWith(push->value()->definition());
|
| + push->RemoveFromGraph();
|
| + }
|
| + // Manually replace call with global null constant. ReplaceCall can't
|
| + // be used for definitions that are already in the graph.
|
| + call->ReplaceUsesWith(flow_graph_->constant_null());
|
| + ASSERT(current_iterator()->Current() == call);
|
| + current_iterator()->RemoveCurrentFromGraph();
|
| + break;
|
| + }
|
| + case MethodRecognizer::kMathMin:
|
| + case MethodRecognizer::kMathMax: {
|
| + // We can handle only monomorphic min/max call sites with both arguments
|
| + // being either doubles or smis.
|
| + if (call->HasICData() && (call->ic_data()->NumberOfChecks() == 1)) {
|
| + const ICData& ic_data = *call->ic_data();
|
| + intptr_t result_cid = kIllegalCid;
|
| + if (ICDataHasReceiverArgumentClassIds(ic_data,
|
| + kDoubleCid, kDoubleCid)) {
|
| + result_cid = kDoubleCid;
|
| + } else if (ICDataHasReceiverArgumentClassIds(ic_data,
|
| + kSmiCid, kSmiCid)) {
|
| + result_cid = kSmiCid;
|
| + }
|
| + if (result_cid != kIllegalCid) {
|
| + MathMinMaxInstr* min_max = new(Z) MathMinMaxInstr(
|
| + recognized_kind,
|
| + new(Z) Value(call->ArgumentAt(0)),
|
| + new(Z) Value(call->ArgumentAt(1)),
|
| + call->deopt_id(),
|
| + result_cid);
|
| + const ICData& unary_checks =
|
| + ICData::ZoneHandle(Z, ic_data.AsUnaryClassChecks());
|
| + AddCheckClass(min_max->left()->definition(),
|
| + unary_checks,
|
| + call->deopt_id(),
|
| + call->env(),
|
| + call);
|
| + AddCheckClass(min_max->right()->definition(),
|
| + unary_checks,
|
| + call->deopt_id(),
|
| + call->env(),
|
| + call);
|
| + ReplaceCall(call, min_max);
|
| }
|
| }
|
| + break;
|
| + }
|
| + case MethodRecognizer::kMathDoublePow:
|
| + case MethodRecognizer::kMathTan:
|
| + case MethodRecognizer::kMathAsin:
|
| + case MethodRecognizer::kMathAcos:
|
| + case MethodRecognizer::kMathAtan:
|
| + case MethodRecognizer::kMathAtan2: {
|
| + if (FLAG_precompilation) {
|
| + // No UnboxDouble instructons allowed.
|
| + return;
|
| + }
|
| + // InvokeMathCFunctionInstr requires unboxed doubles. UnboxDouble
|
| + // instructions contain type checks and conversions to double.
|
| + ZoneGrowableArray<Value*>* args =
|
| + new(Z) ZoneGrowableArray<Value*>(call->ArgumentCount());
|
| + for (intptr_t i = 0; i < call->ArgumentCount(); i++) {
|
| + args->Add(new(Z) Value(call->ArgumentAt(i)));
|
| + }
|
| + InvokeMathCFunctionInstr* invoke =
|
| + new(Z) InvokeMathCFunctionInstr(args,
|
| + call->deopt_id(),
|
| + recognized_kind,
|
| + call->token_pos());
|
| + ReplaceCall(call, invoke);
|
| + break;
|
| }
|
| - } else if (call->function().IsFactory()) {
|
| - const Class& function_class =
|
| - Class::Handle(Z, call->function().Owner());
|
| - if ((function_class.library() == Library::CoreLibrary()) ||
|
| - (function_class.library() == Library::TypedDataLibrary())) {
|
| - intptr_t cid = FactoryRecognizer::ResultCid(call->function());
|
| - switch (cid) {
|
| - case kArrayCid: {
|
| - Value* type = new(Z) Value(call->ArgumentAt(0));
|
| - Value* num_elements = new(Z) Value(call->ArgumentAt(1));
|
| - if (num_elements->BindsToConstant() &&
|
| - num_elements->BoundConstant().IsSmi()) {
|
| - intptr_t length = Smi::Cast(num_elements->BoundConstant()).Value();
|
| - if (length >= 0 && length <= Array::kMaxElements) {
|
| - CreateArrayInstr* create_array =
|
| - new(Z) CreateArrayInstr(
|
| - call->token_pos(), type, num_elements);
|
| - ReplaceCall(call, create_array);
|
| + case MethodRecognizer::kDoubleFromInteger: {
|
| + if (call->HasICData() && (call->ic_data()->NumberOfChecks() == 1)) {
|
| + const ICData& ic_data = *call->ic_data();
|
| + if (CanUnboxDouble()) {
|
| + if (ArgIsAlways(kSmiCid, ic_data, 1)) {
|
| + Definition* arg = call->ArgumentAt(1);
|
| + AddCheckSmi(arg, call->deopt_id(), call->env(), call);
|
| + ReplaceCall(call,
|
| + new(Z) SmiToDoubleInstr(new(Z) Value(arg),
|
| + call->token_pos()));
|
| + } else if (ArgIsAlways(kMintCid, ic_data, 1) &&
|
| + CanConvertUnboxedMintToDouble()) {
|
| + Definition* arg = call->ArgumentAt(1);
|
| + ReplaceCall(call,
|
| + new(Z) MintToDoubleInstr(new(Z) Value(arg),
|
| + call->deopt_id()));
|
| + }
|
| + }
|
| + }
|
| + break;
|
| + }
|
| + default: {
|
| + if (call->function().IsFactory()) {
|
| + const Class& function_class =
|
| + Class::Handle(Z, call->function().Owner());
|
| + if ((function_class.library() == Library::CoreLibrary()) ||
|
| + (function_class.library() == Library::TypedDataLibrary())) {
|
| + intptr_t cid = FactoryRecognizer::ResultCid(call->function());
|
| + switch (cid) {
|
| + case kArrayCid: {
|
| + Value* type = new(Z) Value(call->ArgumentAt(0));
|
| + Value* num_elements = new(Z) Value(call->ArgumentAt(1));
|
| + if (num_elements->BindsToConstant() &&
|
| + num_elements->BoundConstant().IsSmi()) {
|
| + intptr_t length =
|
| + Smi::Cast(num_elements->BoundConstant()).Value();
|
| + if (length >= 0 && length <= Array::kMaxElements) {
|
| + CreateArrayInstr* create_array =
|
| + new(Z) CreateArrayInstr(
|
| + call->token_pos(), type, num_elements);
|
| + ReplaceCall(call, create_array);
|
| + }
|
| + }
|
| }
|
| + default:
|
| + break;
|
| }
|
| }
|
| - default:
|
| - break;
|
| }
|
| }
|
| }
|
|
|