mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 15:17:07 +00:00
VM: More refactoring of recognized methods inlining.
Move inlining OneByteString._setAt, List constructor, Object constructor and a few math function to the flow-graph inliner. Enable inlining of trigonometric math functions in AOT that were previously not inlined. BUG= R=rmacnak@google.com Review URL: https://codereview.chromium.org/2273943002 .
This commit is contained in:
parent
57bff322cd
commit
7d6f78b88f
14 changed files with 224 additions and 501 deletions
|
@ -1216,28 +1216,6 @@ void AotOptimizer::ReplaceWithMathCFunction(
|
|||
}
|
||||
|
||||
|
||||
static bool IsSupportedByteArrayViewCid(intptr_t cid) {
|
||||
switch (cid) {
|
||||
case kTypedDataInt8ArrayCid:
|
||||
case kTypedDataUint8ArrayCid:
|
||||
case kExternalTypedDataUint8ArrayCid:
|
||||
case kTypedDataUint8ClampedArrayCid:
|
||||
case kExternalTypedDataUint8ClampedArrayCid:
|
||||
case kTypedDataInt16ArrayCid:
|
||||
case kTypedDataUint16ArrayCid:
|
||||
case kTypedDataInt32ArrayCid:
|
||||
case kTypedDataUint32ArrayCid:
|
||||
case kTypedDataFloat32ArrayCid:
|
||||
case kTypedDataFloat64ArrayCid:
|
||||
case kTypedDataFloat32x4ArrayCid:
|
||||
case kTypedDataInt32x4ArrayCid:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Inline only simple, frequently called core library methods.
|
||||
bool AotOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) {
|
||||
ASSERT(call->HasICData());
|
||||
|
@ -1253,48 +1231,6 @@ bool AotOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) {
|
|||
MethodRecognizer::Kind recognized_kind =
|
||||
MethodRecognizer::RecognizeKind(target);
|
||||
|
||||
if ((recognized_kind == MethodRecognizer::kOneByteStringCodeUnitAt) ||
|
||||
(recognized_kind == MethodRecognizer::kTwoByteStringCodeUnitAt) ||
|
||||
(recognized_kind == MethodRecognizer::kExternalOneByteStringCodeUnitAt) ||
|
||||
(recognized_kind == MethodRecognizer::kExternalTwoByteStringCodeUnitAt) ||
|
||||
(recognized_kind == MethodRecognizer::kGrowableArraySetData) ||
|
||||
(recognized_kind == MethodRecognizer::kGrowableArraySetLength) ||
|
||||
(recognized_kind == MethodRecognizer::kSmi_bitAndFromSmi)) {
|
||||
return FlowGraphInliner::TryReplaceInstanceCallWithInline(
|
||||
flow_graph_, current_iterator(), call);
|
||||
}
|
||||
|
||||
if (recognized_kind == MethodRecognizer::kStringBaseCharAt) {
|
||||
ASSERT((class_ids[0] == kOneByteStringCid) ||
|
||||
(class_ids[0] == kTwoByteStringCid) ||
|
||||
(class_ids[0] == kExternalOneByteStringCid) ||
|
||||
(class_ids[0] == kExternalTwoByteStringCid));
|
||||
return FlowGraphInliner::TryReplaceInstanceCallWithInline(
|
||||
flow_graph_, current_iterator(), call);
|
||||
}
|
||||
|
||||
if (class_ids[0] == kOneByteStringCid) {
|
||||
if (recognized_kind == MethodRecognizer::kOneByteStringSetAt) {
|
||||
// This is an internal method, no need to check argument types nor
|
||||
// range.
|
||||
Definition* str = call->ArgumentAt(0);
|
||||
Definition* index = call->ArgumentAt(1);
|
||||
Definition* value = call->ArgumentAt(2);
|
||||
StoreIndexedInstr* store_op = new(Z) StoreIndexedInstr(
|
||||
new(Z) Value(str),
|
||||
new(Z) Value(index),
|
||||
new(Z) Value(value),
|
||||
kNoStoreBarrier,
|
||||
1, // Index scale
|
||||
kOneByteStringCid,
|
||||
call->deopt_id(),
|
||||
call->token_pos());
|
||||
ReplaceCall(call, store_op);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (CanUnboxDouble() &&
|
||||
(recognized_kind == MethodRecognizer::kIntegerToDouble)) {
|
||||
if (class_ids[0] == kSmiCid) {
|
||||
|
@ -1353,27 +1289,13 @@ bool AotOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) {
|
|||
ReplaceCall(call, d2d_instr);
|
||||
}
|
||||
return true;
|
||||
case MethodRecognizer::kDoubleAdd:
|
||||
case MethodRecognizer::kDoubleSub:
|
||||
case MethodRecognizer::kDoubleMul:
|
||||
case MethodRecognizer::kDoubleDiv:
|
||||
return FlowGraphInliner::TryReplaceInstanceCallWithInline(
|
||||
flow_graph_, current_iterator(), call);
|
||||
default:
|
||||
// Unsupported method.
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (IsSupportedByteArrayViewCid(class_ids[0]) ||
|
||||
(class_ids[0] == kFloat32x4Cid) ||
|
||||
(class_ids[0] == kInt32x4Cid) ||
|
||||
(class_ids[0] == kFloat64x2Cid)) {
|
||||
return FlowGraphInliner::TryReplaceInstanceCallWithInline(
|
||||
flow_graph_, current_iterator(), call);
|
||||
}
|
||||
|
||||
return false;
|
||||
return FlowGraphInliner::TryReplaceInstanceCallWithInline(
|
||||
flow_graph_, current_iterator(), call);
|
||||
}
|
||||
|
||||
|
||||
|
@ -2030,33 +1952,15 @@ void AotOptimizer::VisitInstanceCall(InstanceCallInstr* instr) {
|
|||
|
||||
|
||||
void AotOptimizer::VisitStaticCall(StaticCallInstr* call) {
|
||||
if (!CanUnboxDouble()) {
|
||||
if (!IsAllowedForInlining(call->deopt_id())) {
|
||||
// Inlining disabled after a speculative inlining attempt.
|
||||
return;
|
||||
}
|
||||
MethodRecognizer::Kind recognized_kind =
|
||||
MethodRecognizer::RecognizeKind(call->function());
|
||||
MathUnaryInstr::MathUnaryKind unary_kind;
|
||||
switch (recognized_kind) {
|
||||
case MethodRecognizer::kMathSqrt:
|
||||
unary_kind = MathUnaryInstr::kSqrt;
|
||||
break;
|
||||
case MethodRecognizer::kMathSin:
|
||||
unary_kind = MathUnaryInstr::kSin;
|
||||
break;
|
||||
case MethodRecognizer::kMathCos:
|
||||
unary_kind = MathUnaryInstr::kCos;
|
||||
break;
|
||||
default:
|
||||
unary_kind = MathUnaryInstr::kIllegal;
|
||||
break;
|
||||
}
|
||||
if (unary_kind != MathUnaryInstr::kIllegal) {
|
||||
ASSERT(FLAG_precompiled_mode);
|
||||
// TODO(srdjan): Adapt MathUnaryInstr to allow tagged inputs as well.
|
||||
return;
|
||||
}
|
||||
|
||||
switch (recognized_kind) {
|
||||
case MethodRecognizer::kObjectConstructor:
|
||||
case MethodRecognizer::kObjectArrayAllocate:
|
||||
case MethodRecognizer::kFloat32x4Zero:
|
||||
case MethodRecognizer::kFloat32x4Splat:
|
||||
case MethodRecognizer::kFloat32x4Constructor:
|
||||
|
@ -2067,31 +1971,25 @@ void AotOptimizer::VisitStaticCall(StaticCallInstr* call) {
|
|||
case MethodRecognizer::kFloat64x2FromFloat32x4:
|
||||
case MethodRecognizer::kInt32x4BoolConstructor:
|
||||
case MethodRecognizer::kInt32x4Constructor:
|
||||
if (!ShouldInlineSimd() || !IsAllowedForInlining(call->deopt_id())) {
|
||||
return;
|
||||
}
|
||||
case MethodRecognizer::kMathSqrt:
|
||||
case MethodRecognizer::kMathDoublePow:
|
||||
case MethodRecognizer::kMathSin:
|
||||
case MethodRecognizer::kMathCos:
|
||||
case MethodRecognizer::kMathTan:
|
||||
case MethodRecognizer::kMathAsin:
|
||||
case MethodRecognizer::kMathAcos:
|
||||
case MethodRecognizer::kMathAtan:
|
||||
case MethodRecognizer::kMathAtan2:
|
||||
FlowGraphInliner::TryReplaceStaticCallWithInline(
|
||||
flow_graph_, current_iterator(), call);
|
||||
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)) {
|
||||
if (CanUnboxDouble() &&
|
||||
call->HasICData() &&
|
||||
(call->ic_data()->NumberOfChecks() == 1)) {
|
||||
const ICData& ic_data = *call->ic_data();
|
||||
intptr_t result_cid = kIllegalCid;
|
||||
if (ICDataHasReceiverArgumentClassIds(ic_data,
|
||||
|
@ -2125,16 +2023,6 @@ void AotOptimizer::VisitStaticCall(StaticCallInstr* call) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case MethodRecognizer::kMathDoublePow:
|
||||
case MethodRecognizer::kMathTan:
|
||||
case MethodRecognizer::kMathAsin:
|
||||
case MethodRecognizer::kMathAcos:
|
||||
case MethodRecognizer::kMathAtan:
|
||||
case MethodRecognizer::kMathAtan2: {
|
||||
ASSERT(FLAG_precompiled_mode);
|
||||
// No UnboxDouble instructions allowed.
|
||||
return;
|
||||
}
|
||||
case MethodRecognizer::kDoubleFromInteger: {
|
||||
if (call->HasICData() && (call->ic_data()->NumberOfChecks() == 1)) {
|
||||
const ICData& ic_data = *call->ic_data();
|
||||
|
@ -2156,35 +2044,8 @@ void AotOptimizer::VisitStaticCall(StaticCallInstr* call) {
|
|||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2060,7 +2060,7 @@ bool FlowGraph::Canonicalize() {
|
|||
void FlowGraph::TryOptimizePatterns() {
|
||||
if (!FLAG_truncating_left_shift) return;
|
||||
GrowableArray<BinarySmiOpInstr*> div_mod_merge;
|
||||
GrowableArray<MathUnaryInstr*> sin_cos_merge;
|
||||
GrowableArray<InvokeMathCFunctionInstr*> sin_cos_merge;
|
||||
for (BlockIterator block_it = reverse_postorder_iterator();
|
||||
!block_it.Done();
|
||||
block_it.Advance()) {
|
||||
|
@ -2090,10 +2090,11 @@ void FlowGraph::TryOptimizePatterns() {
|
|||
mintop->left()->definition(),
|
||||
mintop->right()->definition());
|
||||
}
|
||||
} else if (it.Current()->IsMathUnary()) {
|
||||
MathUnaryInstr* math_unary = it.Current()->AsMathUnary();
|
||||
if ((math_unary->kind() == MathUnaryInstr::kSin) ||
|
||||
(math_unary->kind() == MathUnaryInstr::kCos)) {
|
||||
} else if (it.Current()->IsInvokeMathCFunction()) {
|
||||
InvokeMathCFunctionInstr* math_unary =
|
||||
it.Current()->AsInvokeMathCFunction();
|
||||
if ((math_unary->recognized_kind() == MethodRecognizer::kMathSin) ||
|
||||
(math_unary->recognized_kind() == MethodRecognizer::kMathCos)) {
|
||||
if (math_unary->HasUses()) {
|
||||
sin_cos_merge.Add(math_unary);
|
||||
}
|
||||
|
@ -2195,7 +2196,7 @@ void FlowGraph::TryMergeTruncDivMod(
|
|||
ASSERT((curr_instr->op_kind() == Token::kTRUNCDIV) ||
|
||||
(curr_instr->op_kind() == Token::kMOD));
|
||||
// Check if there is kMOD/kTRUNDIV binop with same inputs.
|
||||
const intptr_t other_kind = (curr_instr->op_kind() == Token::kTRUNCDIV) ?
|
||||
const Token::Kind other_kind = (curr_instr->op_kind() == Token::kTRUNCDIV) ?
|
||||
Token::kMOD : Token::kTRUNCDIV;
|
||||
Definition* left_def = curr_instr->left()->definition();
|
||||
Definition* right_def = curr_instr->right()->definition();
|
||||
|
@ -2242,7 +2243,7 @@ void FlowGraph::TryMergeTruncDivMod(
|
|||
|
||||
// Tries to merge MathUnary operations, in this case sine and cosine.
|
||||
void FlowGraph::TryMergeMathUnary(
|
||||
GrowableArray<MathUnaryInstr*>* merge_candidates) {
|
||||
GrowableArray<InvokeMathCFunctionInstr*>* merge_candidates) {
|
||||
if (!FlowGraphCompiler::SupportsSinCos() || !CanUnboxDouble() ||
|
||||
!FLAG_merge_sin_cos) {
|
||||
return;
|
||||
|
@ -2252,23 +2253,24 @@ void FlowGraph::TryMergeMathUnary(
|
|||
return;
|
||||
}
|
||||
for (intptr_t i = 0; i < merge_candidates->length(); i++) {
|
||||
MathUnaryInstr* curr_instr = (*merge_candidates)[i];
|
||||
InvokeMathCFunctionInstr* curr_instr = (*merge_candidates)[i];
|
||||
if (curr_instr == NULL) {
|
||||
// Instruction was merged already.
|
||||
continue;
|
||||
}
|
||||
const intptr_t kind = curr_instr->kind();
|
||||
ASSERT((kind == MathUnaryInstr::kSin) ||
|
||||
(kind == MathUnaryInstr::kCos));
|
||||
const MethodRecognizer::Kind kind = curr_instr->recognized_kind();
|
||||
ASSERT((kind == MethodRecognizer::kMathSin) ||
|
||||
(kind == MethodRecognizer::kMathCos));
|
||||
// Check if there is sin/cos binop with same inputs.
|
||||
const intptr_t other_kind = (kind == MathUnaryInstr::kSin) ?
|
||||
MathUnaryInstr::kCos : MathUnaryInstr::kSin;
|
||||
Definition* def = curr_instr->value()->definition();
|
||||
const MethodRecognizer::Kind other_kind =
|
||||
(kind == MethodRecognizer::kMathSin)
|
||||
? MethodRecognizer::kMathCos : MethodRecognizer::kMathSin;
|
||||
Definition* def = curr_instr->InputAt(0)->definition();
|
||||
for (intptr_t k = i + 1; k < merge_candidates->length(); k++) {
|
||||
MathUnaryInstr* other_op = (*merge_candidates)[k];
|
||||
InvokeMathCFunctionInstr* other_op = (*merge_candidates)[k];
|
||||
// 'other_op' can be NULL if it was already merged.
|
||||
if ((other_op != NULL) && (other_op->kind() == other_kind) &&
|
||||
(other_op->value()->definition() == def)) {
|
||||
if ((other_op != NULL) && (other_op->recognized_kind() == other_kind) &&
|
||||
(other_op->InputAt(0)->definition() == def)) {
|
||||
(*merge_candidates)[k] = NULL; // Clear it.
|
||||
ASSERT(curr_instr->HasUses());
|
||||
AppendExtractNthOutputForMerged(curr_instr,
|
||||
|
@ -2280,7 +2282,7 @@ void FlowGraph::TryMergeMathUnary(
|
|||
MergedMathInstr::OutputIndexOf(other_kind),
|
||||
kUnboxedDouble, kDoubleCid);
|
||||
ZoneGrowableArray<Value*>* args = new(Z) ZoneGrowableArray<Value*>(1);
|
||||
args->Add(new(Z) Value(curr_instr->value()->definition()));
|
||||
args->Add(new(Z) Value(curr_instr->InputAt(0)->definition()));
|
||||
// Replace with SinCos.
|
||||
MergedMathInstr* sin_cos =
|
||||
new(Z) MergedMathInstr(args,
|
||||
|
|
|
@ -373,7 +373,8 @@ class FlowGraph : public ZoneAllocated {
|
|||
Definition* right_instr);
|
||||
|
||||
void TryMergeTruncDivMod(GrowableArray<BinarySmiOpInstr*>* merge_candidates);
|
||||
void TryMergeMathUnary(GrowableArray<MathUnaryInstr*>* merge_candidates);
|
||||
void TryMergeMathUnary(
|
||||
GrowableArray<InvokeMathCFunctionInstr*>* merge_candidates);
|
||||
|
||||
void AppendExtractNthOutputForMerged(Definition* instr, intptr_t ix,
|
||||
Representation rep, intptr_t cid);
|
||||
|
|
|
@ -2352,6 +2352,9 @@ static bool InlineDoubleOp(FlowGraph* flow_graph,
|
|||
Instruction* call,
|
||||
TargetEntryInstr** entry,
|
||||
Definition** last) {
|
||||
if (!CanUnboxDouble()) {
|
||||
return false;
|
||||
}
|
||||
Definition* left = call->ArgumentAt(0);
|
||||
Definition* right = call->ArgumentAt(1);
|
||||
|
||||
|
@ -2421,7 +2424,7 @@ static bool InlineGrowableArraySetter(FlowGraph* flow_graph,
|
|||
}
|
||||
|
||||
|
||||
static intptr_t PrepareInlineByteArrayBaseOp(
|
||||
static void PrepareInlineByteArrayBaseOp(
|
||||
FlowGraph* flow_graph,
|
||||
Instruction* call,
|
||||
intptr_t array_cid,
|
||||
|
@ -2499,7 +2502,6 @@ static intptr_t PrepareInlineByteArrayBaseOp(
|
|||
FlowGraph::kValue);
|
||||
*array = elements;
|
||||
}
|
||||
return array_cid;
|
||||
}
|
||||
|
||||
|
||||
|
@ -2518,13 +2520,13 @@ static bool InlineByteArrayBaseLoad(FlowGraph* flow_graph,
|
|||
(*entry)->InheritDeoptTarget(Z, call);
|
||||
Instruction* cursor = *entry;
|
||||
|
||||
array_cid = PrepareInlineByteArrayBaseOp(flow_graph,
|
||||
call,
|
||||
array_cid,
|
||||
view_cid,
|
||||
&array,
|
||||
index,
|
||||
&cursor);
|
||||
PrepareInlineByteArrayBaseOp(flow_graph,
|
||||
call,
|
||||
array_cid,
|
||||
view_cid,
|
||||
&array,
|
||||
index,
|
||||
&cursor);
|
||||
|
||||
intptr_t deopt_id = Thread::kNoDeoptId;
|
||||
if ((array_cid == kTypedDataInt32ArrayCid) ||
|
||||
|
@ -2572,13 +2574,13 @@ static bool InlineByteArrayBaseStore(FlowGraph* flow_graph,
|
|||
(*entry)->InheritDeoptTarget(Z, call);
|
||||
Instruction* cursor = *entry;
|
||||
|
||||
array_cid = PrepareInlineByteArrayBaseOp(flow_graph,
|
||||
call,
|
||||
array_cid,
|
||||
view_cid,
|
||||
&array,
|
||||
index,
|
||||
&cursor);
|
||||
PrepareInlineByteArrayBaseOp(flow_graph,
|
||||
call,
|
||||
array_cid,
|
||||
view_cid,
|
||||
&array,
|
||||
index,
|
||||
&cursor);
|
||||
|
||||
// Extract the instance call so we can use the function_name in the stored
|
||||
// value check ICData.
|
||||
|
@ -2874,12 +2876,18 @@ bool FlowGraphInliner::TryReplaceInstanceCallWithInline(
|
|||
push->RemoveFromGraph();
|
||||
}
|
||||
// Replace all uses of this definition with the result.
|
||||
call->ReplaceUsesWith(last);
|
||||
if (call->HasUses()) {
|
||||
call->ReplaceUsesWith(last);
|
||||
}
|
||||
// Finally insert the sequence other definition in place of this one in the
|
||||
// graph.
|
||||
call->previous()->LinkTo(entry->next());
|
||||
if (entry->next() != NULL) {
|
||||
call->previous()->LinkTo(entry->next());
|
||||
}
|
||||
entry->UnuseAllInputs(); // Entry block is not in the graph.
|
||||
last->LinkTo(call);
|
||||
if (last != NULL) {
|
||||
last->LinkTo(call);
|
||||
}
|
||||
// Remove through the iterator.
|
||||
ASSERT(iterator->Current() == call);
|
||||
iterator->RemoveCurrentFromGraph();
|
||||
|
@ -2912,12 +2920,18 @@ bool FlowGraphInliner::TryReplaceStaticCallWithInline(
|
|||
push->RemoveFromGraph();
|
||||
}
|
||||
// Replace all uses of this definition with the result.
|
||||
call->ReplaceUsesWith(last);
|
||||
if (call->HasUses()) {
|
||||
call->ReplaceUsesWith(last);
|
||||
}
|
||||
// Finally insert the sequence other definition in place of this one in the
|
||||
// graph.
|
||||
call->previous()->LinkTo(entry->next());
|
||||
if (entry->next() != NULL) {
|
||||
call->previous()->LinkTo(entry->next());
|
||||
}
|
||||
entry->UnuseAllInputs(); // Entry block is not in the graph.
|
||||
last->LinkTo(call);
|
||||
if (last != NULL) {
|
||||
last->LinkTo(call);
|
||||
}
|
||||
// Remove through the iterator.
|
||||
ASSERT(iterator->Current() == call);
|
||||
iterator->RemoveCurrentFromGraph();
|
||||
|
@ -3327,10 +3341,51 @@ static bool InlineSimdConstructor(FlowGraph* flow_graph,
|
|||
}
|
||||
|
||||
|
||||
static bool InlineMathCFunction(FlowGraph* flow_graph,
|
||||
Instruction* call,
|
||||
MethodRecognizer::Kind kind,
|
||||
TargetEntryInstr** entry,
|
||||
Definition** last) {
|
||||
if (!CanUnboxDouble()) {
|
||||
return false;
|
||||
}
|
||||
*entry = new(Z) TargetEntryInstr(flow_graph->allocate_block_id(),
|
||||
call->GetBlock()->try_index());
|
||||
(*entry)->InheritDeoptTarget(Z, call);
|
||||
Instruction* cursor = *entry;
|
||||
|
||||
switch (kind) {
|
||||
case MethodRecognizer::kMathSqrt: {
|
||||
*last = new(Z) MathUnaryInstr(MathUnaryInstr::kSqrt,
|
||||
new(Z) Value(call->ArgumentAt(0)),
|
||||
call->deopt_id());
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
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)));
|
||||
}
|
||||
*last = new(Z) InvokeMathCFunctionInstr(args,
|
||||
call->deopt_id(),
|
||||
kind,
|
||||
call->token_pos());
|
||||
break;
|
||||
}
|
||||
}
|
||||
flow_graph->AppendTo(cursor, *last,
|
||||
call->deopt_id() != Thread::kNoDeoptId ?
|
||||
call->env() : NULL,
|
||||
FlowGraph::kValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool FlowGraphInliner::TryInlineRecognizedMethod(FlowGraph* flow_graph,
|
||||
intptr_t receiver_cid,
|
||||
const Function& target,
|
||||
Instruction* call,
|
||||
Definition* call,
|
||||
Definition* receiver,
|
||||
TokenPosition token_pos,
|
||||
const ICData& ic_data,
|
||||
|
@ -3653,6 +3708,75 @@ bool FlowGraphInliner::TryInlineRecognizedMethod(FlowGraph* flow_graph,
|
|||
case MethodRecognizer::kInt32x4FromFloat32x4Bits:
|
||||
return InlineSimdConstructor(flow_graph, call, kind, entry, last);
|
||||
|
||||
case MethodRecognizer::kMathSqrt:
|
||||
case MethodRecognizer::kMathDoublePow:
|
||||
case MethodRecognizer::kMathSin:
|
||||
case MethodRecognizer::kMathCos:
|
||||
case MethodRecognizer::kMathTan:
|
||||
case MethodRecognizer::kMathAsin:
|
||||
case MethodRecognizer::kMathAcos:
|
||||
case MethodRecognizer::kMathAtan:
|
||||
case MethodRecognizer::kMathAtan2:
|
||||
return InlineMathCFunction(flow_graph, call, kind, entry, last);
|
||||
|
||||
case MethodRecognizer::kObjectConstructor: {
|
||||
*entry = new(Z) TargetEntryInstr(flow_graph->allocate_block_id(),
|
||||
call->GetBlock()->try_index());
|
||||
(*entry)->InheritDeoptTarget(Z, call);
|
||||
ASSERT(!call->HasUses());
|
||||
*last = NULL; // Empty body.
|
||||
return true;
|
||||
}
|
||||
|
||||
case MethodRecognizer::kObjectArrayAllocate: {
|
||||
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) {
|
||||
Value* type = new(Z) Value(call->ArgumentAt(0));
|
||||
*entry = new(Z) TargetEntryInstr(flow_graph->allocate_block_id(),
|
||||
call->GetBlock()->try_index());
|
||||
(*entry)->InheritDeoptTarget(Z, call);
|
||||
*last =
|
||||
new(Z) CreateArrayInstr(call->token_pos(), type, num_elements);
|
||||
flow_graph->AppendTo(*entry, *last,
|
||||
call->deopt_id() != Thread::kNoDeoptId ?
|
||||
call->env() : NULL,
|
||||
FlowGraph::kValue);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
case MethodRecognizer::kOneByteStringSetAt: {
|
||||
// This is an internal method, no need to check argument types nor
|
||||
// range.
|
||||
*entry = new(Z) TargetEntryInstr(flow_graph->allocate_block_id(),
|
||||
call->GetBlock()->try_index());
|
||||
(*entry)->InheritDeoptTarget(Z, call);
|
||||
Definition* str = call->ArgumentAt(0);
|
||||
Definition* index = call->ArgumentAt(1);
|
||||
Definition* value = call->ArgumentAt(2);
|
||||
*last = new(Z) StoreIndexedInstr(
|
||||
new(Z) Value(str),
|
||||
new(Z) Value(index),
|
||||
new(Z) Value(value),
|
||||
kNoStoreBarrier,
|
||||
1, // Index scale
|
||||
kOneByteStringCid,
|
||||
call->deopt_id(),
|
||||
call->token_pos());
|
||||
flow_graph->AppendTo(*entry,
|
||||
*last,
|
||||
call->deopt_id() != Thread::kNoDeoptId ?
|
||||
call->env() : NULL,
|
||||
FlowGraph::kEffect);
|
||||
return true;
|
||||
}
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ class FlowGraphInliner : ValueObject {
|
|||
static bool TryInlineRecognizedMethod(FlowGraph* flow_graph,
|
||||
intptr_t receiver_cid,
|
||||
const Function& target,
|
||||
Instruction* call,
|
||||
Definition* call,
|
||||
Definition* receiver,
|
||||
TokenPosition token_pos,
|
||||
const ICData& ic_data,
|
||||
|
|
|
@ -3807,24 +3807,9 @@ const RuntimeEntry& InvokeMathCFunctionInstr::TargetFunction() const {
|
|||
}
|
||||
|
||||
|
||||
const RuntimeEntry& MathUnaryInstr::TargetFunction() const {
|
||||
switch (kind()) {
|
||||
case MathUnaryInstr::kSin:
|
||||
return kLibcSinRuntimeEntry;
|
||||
case MathUnaryInstr::kCos:
|
||||
return kLibcCosRuntimeEntry;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
return kLibcSinRuntimeEntry;
|
||||
}
|
||||
|
||||
|
||||
const char* MathUnaryInstr::KindToCString(MathUnaryKind kind) {
|
||||
switch (kind) {
|
||||
case kIllegal: return "illegal";
|
||||
case kSin: return "sin";
|
||||
case kCos: return "cos";
|
||||
case kSqrt: return "sqrt";
|
||||
case kDoubleSquare: return "double-square";
|
||||
}
|
||||
|
@ -3853,10 +3838,10 @@ MergedMathInstr::MergedMathInstr(ZoneGrowableArray<Value*>* inputs,
|
|||
}
|
||||
|
||||
|
||||
intptr_t MergedMathInstr::OutputIndexOf(intptr_t kind) {
|
||||
intptr_t MergedMathInstr::OutputIndexOf(MethodRecognizer::Kind kind) {
|
||||
switch (kind) {
|
||||
case MathUnaryInstr::kSin: return 1;
|
||||
case MathUnaryInstr::kCos: return 0;
|
||||
case MethodRecognizer::kMathSin: return 1;
|
||||
case MethodRecognizer::kMathCos: return 0;
|
||||
default: UNIMPLEMENTED(); return -1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5100,8 +5100,6 @@ class MathUnaryInstr : public TemplateDefinition<1, NoThrow, Pure> {
|
|||
public:
|
||||
enum MathUnaryKind {
|
||||
kIllegal,
|
||||
kSin,
|
||||
kCos,
|
||||
kSqrt,
|
||||
kDoubleSquare,
|
||||
};
|
||||
|
@ -5112,7 +5110,6 @@ class MathUnaryInstr : public TemplateDefinition<1, NoThrow, Pure> {
|
|||
|
||||
Value* value() const { return inputs_[0]; }
|
||||
MathUnaryKind kind() const { return kind_; }
|
||||
const RuntimeEntry& TargetFunction() const;
|
||||
|
||||
virtual bool CanDeoptimize() const { return false; }
|
||||
|
||||
|
@ -7694,7 +7691,7 @@ class MergedMathInstr : public PureDefinition {
|
|||
return (*inputs_)[i];
|
||||
}
|
||||
|
||||
static intptr_t OutputIndexOf(intptr_t kind);
|
||||
static intptr_t OutputIndexOf(MethodRecognizer::Kind kind);
|
||||
static intptr_t OutputIndexOf(Token::Kind token);
|
||||
|
||||
virtual CompileType ComputeType() const;
|
||||
|
|
|
@ -5266,21 +5266,6 @@ void BinaryInt32x4OpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
|
||||
LocationSummary* MathUnaryInstr::MakeLocationSummary(Zone* zone,
|
||||
bool opt) const {
|
||||
if ((kind() == MathUnaryInstr::kSin) || (kind() == MathUnaryInstr::kCos)) {
|
||||
const intptr_t kNumInputs = 1;
|
||||
const intptr_t kNumTemps = TargetCPUFeatures::hardfp_supported() ? 0 : 4;
|
||||
LocationSummary* summary = new(zone) LocationSummary(
|
||||
zone, kNumInputs, kNumTemps, LocationSummary::kCall);
|
||||
summary->set_in(0, Location::FpuRegisterLocation(Q0));
|
||||
summary->set_out(0, Location::FpuRegisterLocation(Q0));
|
||||
if (!TargetCPUFeatures::hardfp_supported()) {
|
||||
summary->set_temp(0, Location::RegisterLocation(R0));
|
||||
summary->set_temp(1, Location::RegisterLocation(R1));
|
||||
summary->set_temp(2, Location::RegisterLocation(R2));
|
||||
summary->set_temp(3, Location::RegisterLocation(R3));
|
||||
}
|
||||
return summary;
|
||||
}
|
||||
ASSERT((kind() == MathUnaryInstr::kSqrt) ||
|
||||
(kind() == MathUnaryInstr::kDoubleSquare));
|
||||
const intptr_t kNumInputs = 1;
|
||||
|
@ -5303,20 +5288,7 @@ void MathUnaryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
const DRegister result = EvenDRegisterOf(locs()->out(0).fpu_reg());
|
||||
__ vmuld(result, val, val);
|
||||
} else {
|
||||
ASSERT((kind() == MathUnaryInstr::kSin) ||
|
||||
(kind() == MathUnaryInstr::kCos));
|
||||
if (TargetCPUFeatures::hardfp_supported()) {
|
||||
__ CallRuntime(TargetFunction(), InputCount());
|
||||
} else {
|
||||
// If we aren't doing "hardfp", then we have to move the double arguments
|
||||
// to the integer registers, and take the results from the integer
|
||||
// registers.
|
||||
__ vmovrrd(R0, R1, D0);
|
||||
__ vmovrrd(R2, R3, D1);
|
||||
__ CallRuntime(TargetFunction(), InputCount());
|
||||
__ vmovdrr(D0, R0, R1);
|
||||
__ vmovdrr(D1, R2, R3);
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4465,15 +4465,6 @@ void BinaryInt32x4OpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
|
||||
LocationSummary* MathUnaryInstr::MakeLocationSummary(Zone* zone,
|
||||
bool opt) const {
|
||||
if ((kind() == MathUnaryInstr::kSin) || (kind() == MathUnaryInstr::kCos)) {
|
||||
const intptr_t kNumInputs = 1;
|
||||
const intptr_t kNumTemps = 0;
|
||||
LocationSummary* summary = new(zone) LocationSummary(
|
||||
zone, kNumInputs, kNumTemps, LocationSummary::kCall);
|
||||
summary->set_in(0, Location::FpuRegisterLocation(V0));
|
||||
summary->set_out(0, Location::FpuRegisterLocation(V0));
|
||||
return summary;
|
||||
}
|
||||
ASSERT((kind() == MathUnaryInstr::kSqrt) ||
|
||||
(kind() == MathUnaryInstr::kDoubleSquare));
|
||||
const intptr_t kNumInputs = 1;
|
||||
|
@ -4496,9 +4487,7 @@ void MathUnaryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
const VRegister result = locs()->out(0).fpu_reg();
|
||||
__ fmuld(result, val, val);
|
||||
} else {
|
||||
ASSERT((kind() == MathUnaryInstr::kSin) ||
|
||||
(kind() == MathUnaryInstr::kCos));
|
||||
__ CallRuntime(TargetFunction(), InputCount());
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1524,10 +1524,6 @@ EMIT_NATIVE_CODE(MathUnary, 1, Location::RequiresRegister()) {
|
|||
__ DSqrt(result, value);
|
||||
} else if (kind() == MathUnaryInstr::kDoubleSquare) {
|
||||
__ DMul(result, value, value);
|
||||
} else if (kind() == MathUnaryInstr::kSin) {
|
||||
__ DSin(result, value);
|
||||
} else if (kind() == MathUnaryInstr::kCos) {
|
||||
__ DCos(result, value);
|
||||
} else {
|
||||
Unsupported(compiler);
|
||||
UNREACHABLE();
|
||||
|
@ -1545,6 +1541,10 @@ EMIT_NATIVE_CODE(InvokeMathCFunction,
|
|||
} else if (recognized_kind() == MethodRecognizer::kDoubleMod) {
|
||||
const Register right = locs()->in(1).reg();
|
||||
__ DMod(result, left, right);
|
||||
} else if (recognized_kind() == MethodRecognizer::kMathSin) {
|
||||
__ DSin(result, left);
|
||||
} else if (recognized_kind() == MethodRecognizer::kMathCos) {
|
||||
__ DCos(result, left);
|
||||
} else {
|
||||
Unsupported(compiler);
|
||||
UNREACHABLE();
|
||||
|
|
|
@ -4904,18 +4904,6 @@ void BinaryInt32x4OpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
|
||||
LocationSummary* MathUnaryInstr::MakeLocationSummary(Zone* zone,
|
||||
bool opt) const {
|
||||
if ((kind() == MathUnaryInstr::kSin) || (kind() == MathUnaryInstr::kCos)) {
|
||||
const intptr_t kNumInputs = 1;
|
||||
const intptr_t kNumTemps = 1;
|
||||
LocationSummary* summary = new(zone) LocationSummary(
|
||||
zone, kNumInputs, kNumTemps, LocationSummary::kCall);
|
||||
summary->set_in(0, Location::FpuRegisterLocation(XMM1));
|
||||
// EDI is chosen because it is callee saved so we do not need to back it
|
||||
// up before calling into the runtime.
|
||||
summary->set_temp(0, Location::RegisterLocation(EDI));
|
||||
summary->set_out(0, Location::FpuRegisterLocation(XMM1));
|
||||
return summary;
|
||||
}
|
||||
ASSERT((kind() == MathUnaryInstr::kSqrt) ||
|
||||
(kind() == MathUnaryInstr::kDoubleSquare));
|
||||
const intptr_t kNumInputs = 1;
|
||||
|
@ -4940,17 +4928,7 @@ void MathUnaryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
__ mulsd(value_reg, value_reg);
|
||||
ASSERT(value_reg == locs()->out(0).fpu_reg());
|
||||
} else {
|
||||
ASSERT((kind() == MathUnaryInstr::kSin) ||
|
||||
(kind() == MathUnaryInstr::kCos));
|
||||
// Save ESP.
|
||||
__ movl(locs()->temp(0).reg(), ESP);
|
||||
__ ReserveAlignedFrameSpace(kDoubleSize * InputCount());
|
||||
__ movsd(Address(ESP, 0), locs()->in(0).fpu_reg());
|
||||
__ CallRuntime(TargetFunction(), InputCount());
|
||||
__ fstpl(Address(ESP, 0));
|
||||
__ movsd(locs()->out(0).fpu_reg(), Address(ESP, 0));
|
||||
// Restore ESP.
|
||||
__ movl(ESP, locs()->temp(0).reg());
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4063,15 +4063,6 @@ void BinaryInt32x4OpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
|
||||
LocationSummary* MathUnaryInstr::MakeLocationSummary(Zone* zone,
|
||||
bool opt) const {
|
||||
if ((kind() == MathUnaryInstr::kSin) || (kind() == MathUnaryInstr::kCos)) {
|
||||
const intptr_t kNumInputs = 1;
|
||||
const intptr_t kNumTemps = 0;
|
||||
LocationSummary* summary = new(zone) LocationSummary(
|
||||
zone, kNumInputs, kNumTemps, LocationSummary::kCall);
|
||||
summary->set_in(0, Location::FpuRegisterLocation(D6));
|
||||
summary->set_out(0, Location::FpuRegisterLocation(D0));
|
||||
return summary;
|
||||
}
|
||||
ASSERT((kind() == MathUnaryInstr::kSqrt) ||
|
||||
(kind() == MathUnaryInstr::kDoubleSquare));
|
||||
const intptr_t kNumInputs = 1;
|
||||
|
@ -4092,7 +4083,7 @@ void MathUnaryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
DRegister result = locs()->out(0).fpu_reg();
|
||||
__ muld(result, val, val);
|
||||
} else {
|
||||
__ CallRuntime(TargetFunction(), InputCount());
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4747,22 +4747,6 @@ void BinaryInt32x4OpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
|
||||
LocationSummary* MathUnaryInstr::MakeLocationSummary(Zone* zone,
|
||||
bool opt) const {
|
||||
if ((kind() == MathUnaryInstr::kSin) || (kind() == MathUnaryInstr::kCos)) {
|
||||
// Calling convention on x64 uses XMM0 and XMM1 to pass the first two
|
||||
// double arguments and XMM0 to return the result. Unfortunately
|
||||
// currently we can't specify these registers because ParallelMoveResolver
|
||||
// assumes that XMM0 is free at all times.
|
||||
// TODO(vegorov): allow XMM0 to be used.
|
||||
const intptr_t kNumTemps = 1;
|
||||
LocationSummary* summary = new(zone) LocationSummary(
|
||||
zone, InputCount(), kNumTemps, LocationSummary::kCall);
|
||||
summary->set_in(0, Location::FpuRegisterLocation(XMM1));
|
||||
// R13 is chosen because it is callee saved so we do not need to back it
|
||||
// up before calling into the runtime.
|
||||
summary->set_temp(0, Location::RegisterLocation(R13));
|
||||
summary->set_out(0, Location::FpuRegisterLocation(XMM1));
|
||||
return summary;
|
||||
}
|
||||
ASSERT((kind() == MathUnaryInstr::kSqrt) ||
|
||||
(kind() == MathUnaryInstr::kDoubleSquare));
|
||||
const intptr_t kNumInputs = 1;
|
||||
|
@ -4787,16 +4771,7 @@ void MathUnaryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
__ mulsd(value_reg, value_reg);
|
||||
ASSERT(value_reg == locs()->out(0).fpu_reg());
|
||||
} else {
|
||||
ASSERT((kind() == MathUnaryInstr::kSin) ||
|
||||
(kind() == MathUnaryInstr::kCos));
|
||||
// Save RSP.
|
||||
__ movq(locs()->temp(0).reg(), RSP);
|
||||
__ ReserveAlignedFrameSpace(0);
|
||||
__ movaps(XMM0, locs()->in(0).fpu_reg());
|
||||
__ CallRuntime(TargetFunction(), InputCount());
|
||||
__ movaps(locs()->out(0).fpu_reg(), XMM0);
|
||||
// Restore RSP.
|
||||
__ movq(RSP, locs()->temp(0).reg());
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1222,28 +1222,6 @@ void JitOptimizer::ReplaceWithMathCFunction(
|
|||
}
|
||||
|
||||
|
||||
static bool IsSupportedByteArrayViewCid(intptr_t cid) {
|
||||
switch (cid) {
|
||||
case kTypedDataInt8ArrayCid:
|
||||
case kTypedDataUint8ArrayCid:
|
||||
case kExternalTypedDataUint8ArrayCid:
|
||||
case kTypedDataUint8ClampedArrayCid:
|
||||
case kExternalTypedDataUint8ClampedArrayCid:
|
||||
case kTypedDataInt16ArrayCid:
|
||||
case kTypedDataUint16ArrayCid:
|
||||
case kTypedDataInt32ArrayCid:
|
||||
case kTypedDataUint32ArrayCid:
|
||||
case kTypedDataFloat32ArrayCid:
|
||||
case kTypedDataFloat64ArrayCid:
|
||||
case kTypedDataFloat32x4ArrayCid:
|
||||
case kTypedDataInt32x4ArrayCid:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Inline only simple, frequently called core library methods.
|
||||
bool JitOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) {
|
||||
ASSERT(call->HasICData());
|
||||
|
@ -1259,48 +1237,6 @@ bool JitOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) {
|
|||
MethodRecognizer::Kind recognized_kind =
|
||||
MethodRecognizer::RecognizeKind(target);
|
||||
|
||||
if ((recognized_kind == MethodRecognizer::kOneByteStringCodeUnitAt) ||
|
||||
(recognized_kind == MethodRecognizer::kTwoByteStringCodeUnitAt) ||
|
||||
(recognized_kind == MethodRecognizer::kExternalOneByteStringCodeUnitAt) ||
|
||||
(recognized_kind == MethodRecognizer::kExternalTwoByteStringCodeUnitAt) ||
|
||||
(recognized_kind == MethodRecognizer::kGrowableArraySetData) ||
|
||||
(recognized_kind == MethodRecognizer::kGrowableArraySetLength) ||
|
||||
(recognized_kind == MethodRecognizer::kSmi_bitAndFromSmi)) {
|
||||
return FlowGraphInliner::TryReplaceInstanceCallWithInline(
|
||||
flow_graph_, current_iterator(), call);
|
||||
}
|
||||
|
||||
if (recognized_kind == MethodRecognizer::kStringBaseCharAt) {
|
||||
ASSERT((class_ids[0] == kOneByteStringCid) ||
|
||||
(class_ids[0] == kTwoByteStringCid) ||
|
||||
(class_ids[0] == kExternalOneByteStringCid) ||
|
||||
(class_ids[0] == kExternalTwoByteStringCid));
|
||||
return FlowGraphInliner::TryReplaceInstanceCallWithInline(
|
||||
flow_graph_, current_iterator(), call);
|
||||
}
|
||||
|
||||
if (class_ids[0] == kOneByteStringCid) {
|
||||
if (recognized_kind == MethodRecognizer::kOneByteStringSetAt) {
|
||||
// This is an internal method, no need to check argument types nor
|
||||
// range.
|
||||
Definition* str = call->ArgumentAt(0);
|
||||
Definition* index = call->ArgumentAt(1);
|
||||
Definition* value = call->ArgumentAt(2);
|
||||
StoreIndexedInstr* store_op = new(Z) StoreIndexedInstr(
|
||||
new(Z) Value(str),
|
||||
new(Z) Value(index),
|
||||
new(Z) Value(value),
|
||||
kNoStoreBarrier,
|
||||
1, // Index scale
|
||||
kOneByteStringCid,
|
||||
call->deopt_id(),
|
||||
call->token_pos());
|
||||
ReplaceCall(call, store_op);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (CanUnboxDouble() &&
|
||||
(recognized_kind == MethodRecognizer::kIntegerToDouble)) {
|
||||
if (class_ids[0] == kSmiCid) {
|
||||
|
@ -1359,27 +1295,13 @@ bool JitOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) {
|
|||
ReplaceCall(call, d2d_instr);
|
||||
}
|
||||
return true;
|
||||
case MethodRecognizer::kDoubleAdd:
|
||||
case MethodRecognizer::kDoubleSub:
|
||||
case MethodRecognizer::kDoubleMul:
|
||||
case MethodRecognizer::kDoubleDiv:
|
||||
return FlowGraphInliner::TryReplaceInstanceCallWithInline(
|
||||
flow_graph_, current_iterator(), call);
|
||||
default:
|
||||
// Unsupported method.
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (IsSupportedByteArrayViewCid(class_ids[0]) ||
|
||||
(class_ids[0] == kFloat32x4Cid) ||
|
||||
(class_ids[0] == kInt32x4Cid) ||
|
||||
(class_ids[0] == kFloat64x2Cid)) {
|
||||
return FlowGraphInliner::TryReplaceInstanceCallWithInline(
|
||||
flow_graph_, current_iterator(), call);
|
||||
}
|
||||
|
||||
return false;
|
||||
return FlowGraphInliner::TryReplaceInstanceCallWithInline(
|
||||
flow_graph_, current_iterator(), call);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1823,35 +1745,11 @@ void JitOptimizer::VisitInstanceCall(InstanceCallInstr* instr) {
|
|||
|
||||
|
||||
void JitOptimizer::VisitStaticCall(StaticCallInstr* call) {
|
||||
if (!CanUnboxDouble()) {
|
||||
return;
|
||||
}
|
||||
MethodRecognizer::Kind recognized_kind =
|
||||
MethodRecognizer::RecognizeKind(call->function());
|
||||
MathUnaryInstr::MathUnaryKind unary_kind;
|
||||
switch (recognized_kind) {
|
||||
case MethodRecognizer::kMathSqrt:
|
||||
unary_kind = MathUnaryInstr::kSqrt;
|
||||
break;
|
||||
case MethodRecognizer::kMathSin:
|
||||
unary_kind = MathUnaryInstr::kSin;
|
||||
break;
|
||||
case MethodRecognizer::kMathCos:
|
||||
unary_kind = MathUnaryInstr::kCos;
|
||||
break;
|
||||
default:
|
||||
unary_kind = MathUnaryInstr::kIllegal;
|
||||
break;
|
||||
}
|
||||
if (unary_kind != MathUnaryInstr::kIllegal) {
|
||||
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::kObjectConstructor:
|
||||
case MethodRecognizer::kObjectArrayAllocate:
|
||||
case MethodRecognizer::kFloat32x4Zero:
|
||||
case MethodRecognizer::kFloat32x4Splat:
|
||||
case MethodRecognizer::kFloat32x4Constructor:
|
||||
|
@ -1862,28 +1760,25 @@ void JitOptimizer::VisitStaticCall(StaticCallInstr* call) {
|
|||
case MethodRecognizer::kFloat64x2FromFloat32x4:
|
||||
case MethodRecognizer::kInt32x4BoolConstructor:
|
||||
case MethodRecognizer::kInt32x4Constructor:
|
||||
case MethodRecognizer::kMathSqrt:
|
||||
case MethodRecognizer::kMathDoublePow:
|
||||
case MethodRecognizer::kMathSin:
|
||||
case MethodRecognizer::kMathCos:
|
||||
case MethodRecognizer::kMathTan:
|
||||
case MethodRecognizer::kMathAsin:
|
||||
case MethodRecognizer::kMathAcos:
|
||||
case MethodRecognizer::kMathAtan:
|
||||
case MethodRecognizer::kMathAtan2:
|
||||
FlowGraphInliner::TryReplaceStaticCallWithInline(
|
||||
flow_graph_, current_iterator(), call);
|
||||
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)) {
|
||||
if (CanUnboxDouble() &&
|
||||
call->HasICData() &&
|
||||
(call->ic_data()->NumberOfChecks() == 1)) {
|
||||
const ICData& ic_data = *call->ic_data();
|
||||
intptr_t result_cid = kIllegalCid;
|
||||
if (ICDataHasReceiverArgumentClassIds(ic_data,
|
||||
|
@ -1917,27 +1812,7 @@ void JitOptimizer::VisitStaticCall(StaticCallInstr* call) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case MethodRecognizer::kMathDoublePow:
|
||||
case MethodRecognizer::kMathTan:
|
||||
case MethodRecognizer::kMathAsin:
|
||||
case MethodRecognizer::kMathAcos:
|
||||
case MethodRecognizer::kMathAtan:
|
||||
case MethodRecognizer::kMathAtan2: {
|
||||
// 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;
|
||||
}
|
||||
|
||||
case MethodRecognizer::kDoubleFromInteger: {
|
||||
if (call->HasICData() && (call->ic_data()->NumberOfChecks() == 1)) {
|
||||
const ICData& ic_data = *call->ic_data();
|
||||
|
@ -1959,35 +1834,8 @@ void JitOptimizer::VisitStaticCall(StaticCallInstr* call) {
|
|||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue