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:
Florian Schneider 2016-08-24 10:35:05 -07:00
parent 57bff322cd
commit 7d6f78b88f
14 changed files with 224 additions and 501 deletions

View file

@ -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;
}
}

View file

@ -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,

View file

@ -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);

View file

@ -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;
}

View file

@ -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,

View file

@ -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;
}
}

View file

@ -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;

View file

@ -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();
}
}

View file

@ -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();
}
}

View file

@ -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();

View file

@ -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();
}
}

View file

@ -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();
}
}

View file

@ -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();
}
}

View file

@ -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;
}
}