Improve polymorphic inlining of int/int double/double operations.

I added inlining of the native Double methods _add, _sub, _mul and _div and fromInteger
and unified the method recognition of the MethodRecognizer and the Intrinsifier classes.

R=srdjan@google.com

Review URL: https://codereview.chromium.org//484693003

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@39446 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
fschneider@google.com 2014-08-21 11:13:44 +00:00
parent 8683cef7cc
commit 937726a0aa
19 changed files with 188 additions and 65 deletions

View file

@ -894,6 +894,37 @@ DEFINE_RUNTIME_ENTRY(InlineCacheMissHandlerThreeArgs, 4) {
}
// Handles a static call in unoptimized code that has one argument type not
// seen before. Compile the target if necessary and update the ICData.
// Arg0: argument.
// Arg1: IC data object.
DEFINE_RUNTIME_ENTRY(StaticCallMissHandlerOneArg, 2) {
const Instance& arg = Instance::CheckedHandle(arguments.ArgAt(0));
const ICData& ic_data = ICData::CheckedHandle(arguments.ArgAt(1));
// IC data for static call is prepopulated with the statically known target.
ASSERT(ic_data.NumberOfChecks() == 1);
const Function& target = Function::Handle(ic_data.GetTargetAt(0));
if (!target.HasCode()) {
const Error& error = Error::Handle(Compiler::CompileFunction(isolate,
target));
if (!error.IsNull()) {
Exceptions::PropagateError(error);
}
}
ASSERT(!target.IsNull() && target.HasCode());
ic_data.AddReceiverCheck(arg.GetClassId(), target, 1);
if (FLAG_trace_ic) {
DartFrameIterator iterator;
StackFrame* caller_frame = iterator.NextFrame();
ASSERT(caller_frame != NULL);
OS::PrintErr("StaticCallMissHandler at %#" Px
" target %s (%" Pd ")\n",
caller_frame->pc(), target.ToCString(), arg.GetClassId());
}
arguments.SetReturn(target);
}
// Handles a static call in unoptimized code that has two argument types not
// seen before. Compile the target if necessary and update the ICData.
// Arg0: argument 0.

View file

@ -27,6 +27,7 @@ DECLARE_RUNTIME_ENTRY(FixCallersTarget);
DECLARE_RUNTIME_ENTRY(InlineCacheMissHandlerOneArg);
DECLARE_RUNTIME_ENTRY(InlineCacheMissHandlerTwoArgs);
DECLARE_RUNTIME_ENTRY(InlineCacheMissHandlerThreeArgs);
DECLARE_RUNTIME_ENTRY(StaticCallMissHandlerOneArg);
DECLARE_RUNTIME_ENTRY(StaticCallMissHandlerTwoArgs);
DECLARE_RUNTIME_ENTRY(Instanceof);
DECLARE_RUNTIME_ENTRY(TypeCheck);

View file

@ -1296,15 +1296,9 @@ void FlowGraphCompiler::EmitUnoptimizedStaticCall(
intptr_t token_pos,
LocationSummary* locs,
const ICData& ic_data) {
uword label_address = 0;
StubCode* stub_code = isolate()->stub_code();
if (ic_data.NumArgsTested() == 0) {
label_address = stub_code->ZeroArgsUnoptimizedStaticCallEntryPoint();
} else if (ic_data.NumArgsTested() == 2) {
label_address = stub_code->TwoArgsUnoptimizedStaticCallEntryPoint();
} else {
UNIMPLEMENTED();
}
const uword label_address =
stub_code->UnoptimizedStaticCallEntryPoint(ic_data.NumArgsTested());
ExternalLabel target_label(label_address);
__ LoadObject(R5, ic_data);
GenerateDartCall(deopt_id,

View file

@ -1301,15 +1301,9 @@ void FlowGraphCompiler::EmitUnoptimizedStaticCall(
intptr_t token_pos,
LocationSummary* locs,
const ICData& ic_data) {
uword label_address = 0;
StubCode* stub_code = isolate()->stub_code();
if (ic_data.NumArgsTested() == 0) {
label_address = stub_code->ZeroArgsUnoptimizedStaticCallEntryPoint();
} else if (ic_data.NumArgsTested() == 2) {
label_address = stub_code->TwoArgsUnoptimizedStaticCallEntryPoint();
} else {
UNIMPLEMENTED();
}
const uword label_address =
stub_code->UnoptimizedStaticCallEntryPoint(ic_data.NumArgsTested());
ExternalLabel target_label(label_address);
__ LoadObject(R5, ic_data, PP);
GenerateDartCall(deopt_id,

View file

@ -1178,15 +1178,9 @@ void FlowGraphCompiler::EmitUnoptimizedStaticCall(
intptr_t token_pos,
LocationSummary* locs,
const ICData& ic_data) {
uword label_address = 0;
StubCode* stub_code = isolate()->stub_code();
if (ic_data.NumArgsTested() == 0) {
label_address = stub_code->ZeroArgsUnoptimizedStaticCallEntryPoint();
} else if (ic_data.NumArgsTested() == 2) {
label_address = stub_code->TwoArgsUnoptimizedStaticCallEntryPoint();
} else {
UNIMPLEMENTED();
}
const uword label_address =
stub_code->UnoptimizedStaticCallEntryPoint(ic_data.NumArgsTested());
ExternalLabel target_label(label_address);
__ LoadObject(ECX, ic_data);
GenerateDartCall(deopt_id,

View file

@ -1337,15 +1337,9 @@ void FlowGraphCompiler::EmitUnoptimizedStaticCall(
intptr_t token_pos,
LocationSummary* locs,
const ICData& ic_data) {
uword label_address = 0;
StubCode* stub_code = isolate()->stub_code();
if (ic_data.NumArgsTested() == 0) {
label_address = stub_code->ZeroArgsUnoptimizedStaticCallEntryPoint();
} else if (ic_data.NumArgsTested() == 2) {
label_address = stub_code->TwoArgsUnoptimizedStaticCallEntryPoint();
} else {
UNIMPLEMENTED();
}
const uword label_address =
stub_code->UnoptimizedStaticCallEntryPoint(ic_data.NumArgsTested());
ExternalLabel target_label(label_address);
__ LoadObject(S5, ic_data);
GenerateDartCall(deopt_id,

View file

@ -1215,15 +1215,9 @@ void FlowGraphCompiler::EmitUnoptimizedStaticCall(
intptr_t token_pos,
LocationSummary* locs,
const ICData& ic_data) {
uword label_address = 0;
StubCode* stub_code = isolate()->stub_code();
if (ic_data.NumArgsTested() == 0) {
label_address = stub_code->ZeroArgsUnoptimizedStaticCallEntryPoint();
} else if (ic_data.NumArgsTested() == 2) {
label_address = stub_code->TwoArgsUnoptimizedStaticCallEntryPoint();
} else {
UNIMPLEMENTED();
}
const uword label_address =
stub_code->UnoptimizedStaticCallEntryPoint(ic_data.NumArgsTested());
ExternalLabel target_label(label_address);
__ LoadObject(RBX, ic_data, PP);
GenerateDartCall(deopt_id,

View file

@ -1560,6 +1560,14 @@ bool FlowGraphOptimizer::TryInlineRecognizedMethod(intptr_t receiver_cid,
return InlineStringCodeUnitAt(call, receiver_cid, entry, last);
case MethodRecognizer::kStringBaseCharAt:
return InlineStringBaseCharAt(call, receiver_cid, entry, last);
case MethodRecognizer::kDoubleAdd:
return InlineDoubleOp(Token::kADD, call, entry, last);
case MethodRecognizer::kDoubleSub:
return InlineDoubleOp(Token::kSUB, call, entry, last);
case MethodRecognizer::kDoubleMul:
return InlineDoubleOp(Token::kMUL, call, entry, last);
case MethodRecognizer::kDoubleDiv:
return InlineDoubleOp(Token::kDIV, call, entry, last);
default:
return false;
}
@ -2336,21 +2344,6 @@ void FlowGraphOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call) {
}
LoadFieldInstr* FlowGraphOptimizer::BuildLoadStringLength(Definition* str) {
// Treat length loads as mutable (i.e. affected by side effects) to avoid
// hoisting them since we can't hoist the preceding class-check. This
// is because of externalization of strings that affects their class-id.
LoadFieldInstr* load = new(I) LoadFieldInstr(
new(I) Value(str),
String::length_offset(),
Type::ZoneHandle(I, Type::SmiType()),
str->token_pos());
load->set_result_cid(kSmiCid);
load->set_recognized_kind(MethodRecognizer::kStringBaseLength);
return load;
}
bool FlowGraphOptimizer::InlineFloat32x4Getter(InstanceCallInstr* call,
MethodRecognizer::Kind getter) {
if (!ShouldInlineSimd()) {
@ -2711,7 +2704,17 @@ Definition* FlowGraphOptimizer::PrepareInlineStringIndexOp(
FlowGraph::kEffect);
// Load the length of the string.
LoadFieldInstr* length = BuildLoadStringLength(str);
// Treat length loads as mutable (i.e. affected by side effects) to avoid
// hoisting them since we can't hoist the preceding class-check. This
// is because of externalization of strings that affects their class-id.
LoadFieldInstr* length = new(I) LoadFieldInstr(
new(I) Value(str),
String::length_offset(),
Type::ZoneHandle(I, Type::SmiType()),
str->token_pos());
length->set_result_cid(kSmiCid);
length->set_recognized_kind(MethodRecognizer::kStringBaseLength);
cursor = flow_graph()->AppendTo(cursor, length, NULL, FlowGraph::kValue);
// Bounds check.
cursor = flow_graph()->AppendTo(cursor,
@ -2790,6 +2793,30 @@ bool FlowGraphOptimizer::InlineStringBaseCharAt(
}
bool FlowGraphOptimizer::InlineDoubleOp(
Token::Kind op_kind,
Instruction* call,
TargetEntryInstr** entry,
Definition** last) {
Definition* left = call->ArgumentAt(0);
Definition* right = call->ArgumentAt(1);
*entry = new(I) TargetEntryInstr(flow_graph()->allocate_block_id(),
call->GetBlock()->try_index());
(*entry)->InheritDeoptTarget(I, call);
// Arguments are checked. No need for class check.
BinaryDoubleOpInstr* double_bin_op =
new(I) BinaryDoubleOpInstr(op_kind,
new(I) Value(left),
new(I) Value(right),
call->deopt_id(), call->token_pos());
flow_graph()->AppendTo(*entry, double_bin_op, call->env(), FlowGraph::kValue);
*last = double_bin_op;
return true;
}
void FlowGraphOptimizer::ReplaceWithMathCFunction(
InstanceCallInstr* call,
MethodRecognizer::Kind recognized_kind) {
@ -2960,6 +2987,11 @@ bool FlowGraphOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) {
ReplaceCall(call, d2d_instr);
}
return true;
case MethodRecognizer::kDoubleAdd:
case MethodRecognizer::kDoubleSub:
case MethodRecognizer::kDoubleMul:
case MethodRecognizer::kDoubleDiv:
return TryReplaceInstanceCallWithInline(call);
default:
// Unsupported method.
return false;
@ -4342,6 +4374,23 @@ void FlowGraphOptimizer::VisitStaticCall(StaticCallInstr* call) {
CreateArrayInstr* create_array =
new(I) CreateArrayInstr(call->token_pos(), type, num_elements);
ReplaceCall(call, create_array);
} else if (recognized_kind == MethodRecognizer::kDoubleFromInteger) {
if (call->HasICData() && (call->ic_data()->NumberOfChecks() == 1)) {
const ICData& ic_data = *call->ic_data();
if (CanUnboxDouble() && ArgIsAlways(kSmiCid, ic_data, 0)) {
Definition* arg = call->ArgumentAt(0);
InsertBefore(call,
new(I) CheckSmiInstr(
new(I) Value(arg),
call->deopt_id(),
call->token_pos()),
call->env(),
FlowGraph::kEffect);
ReplaceCall(call,
new(I) SmiToDoubleInstr(new(I) Value(arg),
call->token_pos()));
}
}
} else if (call->function().IsFactory()) {
const Class& function_class =
Class::Handle(I, call->function().Owner());

View file

@ -131,8 +131,6 @@ class FlowGraphOptimizer : public FlowGraphVisitor {
bool TryReplaceInstanceCallWithInline(InstanceCallInstr* call);
LoadFieldInstr* BuildLoadStringLength(Definition* str);
Definition* PrepareInlineStringIndexOp(Instruction* call,
intptr_t cid,
Definition* str,
@ -149,6 +147,11 @@ class FlowGraphOptimizer : public FlowGraphVisitor {
TargetEntryInstr** entry,
Definition** last);
bool InlineDoubleOp(Token::Kind op_kind,
Instruction* call,
TargetEntryInstr** entry,
Definition** last);
bool InlineByteArrayViewLoad(Instruction* call,
Definition* receiver,
intptr_t array_cid,

View file

@ -2312,9 +2312,16 @@ void StaticCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
MethodRecognizer::Kind recognized_kind =
MethodRecognizer::RecognizeKind(function());
int num_args_checked = 0;
if ((recognized_kind == MethodRecognizer::kMathMin) ||
(recognized_kind == MethodRecognizer::kMathMax)) {
num_args_checked = 2;
switch (recognized_kind) {
case MethodRecognizer::kDoubleFromInteger:
num_args_checked = 1;
break;
case MethodRecognizer::kMathMin:
case MethodRecognizer::kMathMax:
num_args_checked = 2;
break;
default:
break;
}
call_ic_data = compiler->GetOrAddStaticCallICData(deopt_id(),
function(),

View file

@ -42,11 +42,16 @@ namespace dart {
V(_IntegerImplementation, toDouble, IntegerToDouble, 1084977108) \
V(_IntegerImplementation, _leftShiftWithMask32, IntegerLeftShiftWithMask32, \
597111055) \
V(_Double, .fromInteger, DoubleFromInteger, 999771940) \
V(_Double, truncateToDouble, DoubleTruncate, 2117801967) \
V(_Double, roundToDouble, DoubleRound, 2124216110) \
V(_Double, floorToDouble, DoubleFloor, 968600699) \
V(_Double, ceilToDouble, DoubleCeil, 1779929274) \
V(_Double, _modulo, DoubleMod, 1473971007) \
V(_Double, _add, DoubleAdd, 1570715125) \
V(_Double, _sub, DoubleSub, 1466395310) \
V(_Double, _mul, DoubleMul, 546441193) \
V(_Double, _div, DoubleDiv, 1201505037) \
V(::, sin, MathSin, 1741396147) \
V(::, cos, MathCos, 1951197905) \
V(::, min, MathMin, 1022567780) \

View file

@ -11351,11 +11351,15 @@ void ICData::AddTarget(const Function& target) const {
ASSERT(!target.IsNull());
if (NumArgsTested() > 0) {
// Create a fake cid entry, so that we can store the target.
GrowableArray<intptr_t> class_ids(NumArgsTested());
for (intptr_t i = 0; i < NumArgsTested(); i++) {
class_ids.Add(kObjectCid);
if (NumArgsTested() == 1) {
AddReceiverCheck(kObjectCid, target, 1);
} else {
GrowableArray<intptr_t> class_ids(NumArgsTested());
for (intptr_t i = 0; i < NumArgsTested(); i++) {
class_ids.Add(kObjectCid);
}
AddCheck(class_ids, target);
}
AddCheck(class_ids, target);
return;
}
ASSERT(NumArgsTested() >= 0);

View file

@ -133,6 +133,21 @@ RawCode* StubCode::GetAllocationStubForClass(const Class& cls) {
}
uword StubCode::UnoptimizedStaticCallEntryPoint(intptr_t num_args_tested) {
switch (num_args_tested) {
case 0:
return ZeroArgsUnoptimizedStaticCallEntryPoint();
case 1:
return OneArgUnoptimizedStaticCallEntryPoint();
case 2:
return TwoArgsUnoptimizedStaticCallEntryPoint();
default:
UNIMPLEMENTED();
return 0;
}
}
RawCode* StubCode::Generate(const char* name,
void (*GenerateStub)(Assembler* assembler)) {
Assembler assembler;

View file

@ -62,6 +62,7 @@ class RawCode;
V(ThreeArgsOptimizedCheckInlineCache) \
V(ClosureCallInlineCache) \
V(ZeroArgsUnoptimizedStaticCall) \
V(OneArgUnoptimizedStaticCall) \
V(TwoArgsUnoptimizedStaticCall) \
V(OptimizeFunction) \
V(InvokeDartCode) \
@ -162,6 +163,8 @@ class StubCode {
static RawCode* GetAllocationStubForClass(const Class& cls);
uword UnoptimizedStaticCallEntryPoint(intptr_t num_args_tested);
static const intptr_t kNoInstantiator = 0;
private:

View file

@ -1494,6 +1494,13 @@ void StubCode::GenerateZeroArgsUnoptimizedStaticCallStub(Assembler* assembler) {
}
void StubCode::GenerateOneArgUnoptimizedStaticCallStub(Assembler* assembler) {
GenerateUsageCounterIncrement(assembler, R6);
GenerateNArgsCheckInlineCacheStub(
assembler, 1, kStaticCallMissHandlerOneArgRuntimeEntry);
}
void StubCode::GenerateTwoArgsUnoptimizedStaticCallStub(Assembler* assembler) {
GenerateUsageCounterIncrement(assembler, R6);
GenerateNArgsCheckInlineCacheStub(

View file

@ -1602,6 +1602,13 @@ void StubCode::GenerateZeroArgsUnoptimizedStaticCallStub(Assembler* assembler) {
}
void StubCode::GenerateOneArgUnoptimizedStaticCallStub(Assembler* assembler) {
GenerateUsageCounterIncrement(assembler, R6);
GenerateNArgsCheckInlineCacheStub(
assembler, 1, kStaticCallMissHandlerOneArgRuntimeEntry);
}
void StubCode::GenerateTwoArgsUnoptimizedStaticCallStub(Assembler* assembler) {
GenerateUsageCounterIncrement(assembler, R6);
GenerateNArgsCheckInlineCacheStub(

View file

@ -1552,6 +1552,13 @@ void StubCode::GenerateZeroArgsUnoptimizedStaticCallStub(Assembler* assembler) {
}
void StubCode::GenerateOneArgUnoptimizedStaticCallStub(Assembler* assembler) {
GenerateUsageCounterIncrement(assembler, EBX);
GenerateNArgsCheckInlineCacheStub(
assembler, 1, kStaticCallMissHandlerOneArgRuntimeEntry);
}
void StubCode::GenerateTwoArgsUnoptimizedStaticCallStub(Assembler* assembler) {
GenerateUsageCounterIncrement(assembler, EBX);
GenerateNArgsCheckInlineCacheStub(

View file

@ -1686,6 +1686,13 @@ void StubCode::GenerateZeroArgsUnoptimizedStaticCallStub(Assembler* assembler) {
}
void StubCode::GenerateOneArgUnoptimizedStaticCallStub(Assembler* assembler) {
GenerateUsageCounterIncrement(assembler, T0);
GenerateNArgsCheckInlineCacheStub(
assembler, 1, kStaticCallMissHandlerOneArgRuntimeEntry);
}
void StubCode::GenerateTwoArgsUnoptimizedStaticCallStub(Assembler* assembler) {
GenerateUsageCounterIncrement(assembler, T0);
GenerateNArgsCheckInlineCacheStub(

View file

@ -1518,6 +1518,13 @@ void StubCode::GenerateZeroArgsUnoptimizedStaticCallStub(Assembler* assembler) {
}
void StubCode::GenerateOneArgUnoptimizedStaticCallStub(Assembler* assembler) {
GenerateUsageCounterIncrement(assembler, RCX);
GenerateNArgsCheckInlineCacheStub(
assembler, 1, kStaticCallMissHandlerOneArgRuntimeEntry);
}
void StubCode::GenerateTwoArgsUnoptimizedStaticCallStub(Assembler* assembler) {
GenerateUsageCounterIncrement(assembler, RCX);
GenerateNArgsCheckInlineCacheStub(