30 compiler_->is_optimizing_ =
true;
33 compiler_->is_optimizing_ = old_is_optimizing_;
38 bool old_is_optimizing_;
43static void EmitCodeFor(FlowGraphCompiler*
compiler, FlowGraph* graph) {
47 GraphIntrinsicCodeGenScope optimizing_scope(
compiler);
49 compiler->assembler()->Comment(
"Graph intrinsic begin");
50 for (intptr_t i = 0; i < graph->reverse_postorder().
length(); i++) {
51 BlockEntryInstr* block = graph->reverse_postorder()[i];
52 if (block->IsGraphEntry())
continue;
54 if (block->HasParallelMove()) {
55 block->parallel_move()->EmitNativeCode(
compiler);
58 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
59 Instruction* instr = it.Current();
60 if (FLAG_code_comments)
compiler->EmitComment(instr);
62 ASSERT(instr->IsParallelMove() ||
63 (instr->locs() !=
nullptr && !instr->locs()->always_calls()));
67 compiler->assembler()->Comment(
"Graph intrinsic end");
78 intptr_t block_id = 1;
79 graph_entry->set_normal_entry(
84 new FlowGraph(parsed_function, graph_entry, block_id, prologue_info,
86 compiler->set_intrinsic_flow_graph(*graph);
90 switch (
function.recognized_kind()) {
91#define EMIT_CASE(class_name, function_name, enum_name, fp) \
92 case MethodRecognizer::k##enum_name: \
93 if (!Build_##enum_name(graph)) return false; \
134 return kUnboxedDouble;
136 return kUnboxedFloat32x4;
138 return kUnboxedInt32x4;
140 return kUnboxedFloat64x2;
143 return kNoRepresentation;
152static Definition* PrepareIndexedOp(FlowGraph* flow_graph,
153 BlockBuilder* builder,
156 const Slot& length_field) {
157 Definition*
length = builder->AddDefinition(
158 new LoadFieldInstr(
new Value(array), length_field, InstructionSource()));
161 Definition* safe_index =
new CheckArrayBoundInstr(
163 builder->AddDefinition(safe_index);
167static void VerifyParameterIsBoxed(BlockBuilder* builder, intptr_t arg_index) {
169 if (
function.is_unboxed_parameter_at(arg_index)) {
170 FATAL(
"Unsupported unboxed parameter %" Pd " in %s", arg_index,
171 function.ToFullyQualifiedCString());
175static Definition* CreateBoxedParameterIfNeeded(BlockBuilder* builder,
178 intptr_t arg_index) {
180 if (
function.is_unboxed_parameter_at(arg_index)) {
188static Definition* CreateBoxedResultIfNeeded(BlockBuilder* builder,
194 if (representation == kUnboxedFloat) {
197 representation = kUnboxedDouble;
199 if (!
function.has_unboxed_return()) {
206static Definition* CreateUnboxedResultIfNeeded(BlockBuilder* builder,
210 if (
function.has_unboxed_return() &&
value->representation() == kTagged) {
212 new Value(value),
true);
218static bool IntrinsifyArraySetIndexed(FlowGraph* flow_graph,
219 intptr_t array_cid) {
220 GraphEntryInstr* graph_entry = flow_graph->graph_entry();
221 auto normal_entry = graph_entry->normal_entry();
222 BlockBuilder
builder(flow_graph, normal_entry,
false);
224 Definition* array =
builder.AddParameter(0);
225 Definition* index =
builder.AddParameter(1);
228 VerifyParameterIsBoxed(&builder, 0);
229 VerifyParameterIsBoxed(&builder, 2);
231 index = CreateBoxedParameterIfNeeded(&builder, index, kUnboxedInt64, 1);
232 index = PrepareIndexedOp(flow_graph, &builder, array, index,
238#if defined(TARGET_ARCH_IS_32_BIT)
249 auto const unbox_rep = rep == kUnboxedInt32 ? kUnboxedUint32 : rep;
253 Zone* zone = flow_graph->zone();
256 *value_check,
builder.Source()));
262 array =
builder.AddDefinition(
new LoadFieldInstr(
263 new Value(array), Slot::PointerBase_data(),
269 builder.AddInstruction(
new StoreIndexedInstr(
272 target::Instance::ElementSizeFor(array_cid), array_cid,
275 Definition* null_def =
builder.AddNullDefinition();
280#define DEFINE_ARRAY_SETTER_INTRINSIC(enum_name) \
281 bool GraphIntrinsifier::Build_##enum_name##SetIndexed( \
282 FlowGraph* flow_graph) { \
283 return IntrinsifyArraySetIndexed( \
284 flow_graph, MethodRecognizer::MethodKindToReceiverCid( \
285 MethodRecognizer::k##enum_name##SetIndexed)); \
300#undef DEFINE_ARRAY_SETTER_INTRINSIC
302#define DEFINE_FLOAT_ARRAY_SETTER_INTRINSIC(enum_name) \
303 bool GraphIntrinsifier::Build_##enum_name##SetIndexed( \
304 FlowGraph* flow_graph) { \
305 if (!FlowGraphCompiler::SupportsUnboxedDoubles()) { \
308 return IntrinsifyArraySetIndexed( \
309 flow_graph, MethodRecognizer::MethodKindToReceiverCid( \
310 MethodRecognizer::k##enum_name##SetIndexed)); \
316#undef DEFINE_FLOAT_ARRAY_SETTER_INTRINSIC
318#define DEFINE_SIMD_ARRAY_SETTER_INTRINSIC(enum_name) \
319 bool GraphIntrinsifier::Build_##enum_name##SetIndexed( \
320 FlowGraph* flow_graph) { \
321 if (!FlowGraphCompiler::SupportsUnboxedSimd128()) { \
324 return IntrinsifyArraySetIndexed( \
325 flow_graph, MethodRecognizer::MethodKindToReceiverCid( \
326 MethodRecognizer::k##enum_name##SetIndexed)); \
333#undef DEFINE_SIMD_ARRAY_SETTER_INTRINSIC
335static bool BuildSimdOp(FlowGraph* flow_graph, intptr_t
cid,
Token::Kind kind) {
338 auto const rep = RepresentationForCid(
cid);
340 Zone* zone = flow_graph->zone();
341 GraphEntryInstr* graph_entry = flow_graph->graph_entry();
342 auto normal_entry = graph_entry->normal_entry();
343 BlockBuilder builder(flow_graph, normal_entry,
false);
345 Definition*
left = builder.AddParameter(0);
346 Definition*
right = builder.AddParameter(1);
348 VerifyParameterIsBoxed(&builder, 0);
349 VerifyParameterIsBoxed(&builder, 1);
354 *value_check, builder.Source()));
355 Definition* left_simd = builder.AddUnboxInstr(rep,
new Value(
left),
358 Definition* right_simd = builder.AddUnboxInstr(rep,
new Value(
right),
364 Definition*
result = CreateBoxedResultIfNeeded(&builder, unboxed_result, rep);
370bool GraphIntrinsifier::Build_Float32x4Mul(FlowGraph* flow_graph) {
371 return BuildSimdOp(flow_graph, kFloat32x4Cid, Token::kMUL);
374bool GraphIntrinsifier::Build_Float32x4Div(FlowGraph* flow_graph) {
375 return BuildSimdOp(flow_graph, kFloat32x4Cid, Token::kDIV);
378bool GraphIntrinsifier::Build_Float32x4Sub(FlowGraph* flow_graph) {
379 return BuildSimdOp(flow_graph, kFloat32x4Cid, Token::kSUB);
382bool GraphIntrinsifier::Build_Float32x4Add(FlowGraph* flow_graph) {
383 return BuildSimdOp(flow_graph, kFloat32x4Cid, Token::kADD);
386bool GraphIntrinsifier::Build_Float64x2Mul(FlowGraph* flow_graph) {
387 return BuildSimdOp(flow_graph, kFloat64x2Cid, Token::kMUL);
390bool GraphIntrinsifier::Build_Float64x2Div(FlowGraph* flow_graph) {
391 return BuildSimdOp(flow_graph, kFloat64x2Cid, Token::kDIV);
394bool GraphIntrinsifier::Build_Float64x2Sub(FlowGraph* flow_graph) {
395 return BuildSimdOp(flow_graph, kFloat64x2Cid, Token::kSUB);
398bool GraphIntrinsifier::Build_Float64x2Add(FlowGraph* flow_graph) {
399 return BuildSimdOp(flow_graph, kFloat64x2Cid, Token::kADD);
402static bool BuildFloat32x4Get(FlowGraph* flow_graph,
408 GraphEntryInstr* graph_entry = flow_graph->graph_entry();
409 auto normal_entry = graph_entry->normal_entry();
410 BlockBuilder
builder(flow_graph, normal_entry,
false);
412 Definition* receiver =
builder.AddParameter(0);
414 const auto&
function = flow_graph->function();
415 Definition* unboxed_receiver =
416 !
function.is_unboxed_parameter_at(0)
417 ?
builder.AddUnboxInstr(kUnboxedFloat32x4,
new Value(receiver),
421 Definition* unboxed_result =
builder.AddDefinition(
425 CreateBoxedResultIfNeeded(&builder, unboxed_result, kUnboxedDouble);
431bool GraphIntrinsifier::Build_Float32x4GetX(FlowGraph* flow_graph) {
432 return BuildFloat32x4Get(flow_graph, MethodRecognizer::kFloat32x4GetX);
435bool GraphIntrinsifier::Build_Float32x4GetY(FlowGraph* flow_graph) {
436 return BuildFloat32x4Get(flow_graph, MethodRecognizer::kFloat32x4GetY);
439bool GraphIntrinsifier::Build_Float32x4GetZ(FlowGraph* flow_graph) {
440 return BuildFloat32x4Get(flow_graph, MethodRecognizer::kFloat32x4GetZ);
443bool GraphIntrinsifier::Build_Float32x4GetW(FlowGraph* flow_graph) {
444 return BuildFloat32x4Get(flow_graph, MethodRecognizer::kFloat32x4GetW);
447static bool BuildLoadField(FlowGraph* flow_graph,
const Slot& field) {
448 GraphEntryInstr* graph_entry = flow_graph->graph_entry();
449 auto normal_entry = graph_entry->normal_entry();
450 BlockBuilder
builder(flow_graph, normal_entry,
false);
452 Definition* array =
builder.AddParameter(0);
453 VerifyParameterIsBoxed(&builder, 0);
456 new LoadFieldInstr(
new Value(array), field,
builder.Source()));
463bool GraphIntrinsifier::Build_ObjectArrayLength(FlowGraph* flow_graph) {
464 return BuildLoadField(flow_graph, Slot::Array_length());
467bool GraphIntrinsifier::Build_GrowableArrayLength(FlowGraph* flow_graph) {
468 return BuildLoadField(flow_graph, Slot::GrowableObjectArray_length());
471bool GraphIntrinsifier::Build_StringBaseLength(FlowGraph* flow_graph) {
472 return BuildLoadField(flow_graph, Slot::String_length());
475bool GraphIntrinsifier::Build_TypedListBaseLength(FlowGraph* flow_graph) {
476 return BuildLoadField(flow_graph, Slot::TypedDataBase_length());
479bool GraphIntrinsifier::Build_ByteDataViewLength(FlowGraph* flow_graph) {
480 return BuildLoadField(flow_graph, Slot::TypedDataBase_length());
483bool GraphIntrinsifier::Build_GrowableArrayCapacity(FlowGraph* flow_graph) {
484 GraphEntryInstr* graph_entry = flow_graph->graph_entry();
485 auto normal_entry = graph_entry->normal_entry();
486 BlockBuilder
builder(flow_graph, normal_entry,
false);
488 Definition* array =
builder.AddParameter(0);
489 VerifyParameterIsBoxed(&builder, 0);
491 Definition* backing_store =
builder.AddDefinition(
new LoadFieldInstr(
492 new Value(array), Slot::GrowableObjectArray_data(),
builder.Source()));
493 Definition* capacity =
builder.AddDefinition(
new LoadFieldInstr(
494 new Value(backing_store), Slot::Array_length(),
builder.Source()));
495 capacity = CreateUnboxedResultIfNeeded(&builder, capacity);
500bool GraphIntrinsifier::Build_ObjectArraySetIndexedUnchecked(
501 FlowGraph* flow_graph) {
502 GraphEntryInstr* graph_entry = flow_graph->graph_entry();
503 auto normal_entry = graph_entry->normal_entry();
504 BlockBuilder
builder(flow_graph, normal_entry,
false);
506 Definition* array =
builder.AddParameter(0);
507 Definition* index =
builder.AddParameter(1);
510 VerifyParameterIsBoxed(&builder, 0);
511 VerifyParameterIsBoxed(&builder, 2);
513 index = CreateBoxedParameterIfNeeded(&builder, index, kUnboxedInt64, 1);
514 index = PrepareIndexedOp(flow_graph, &builder, array, index,
515 Slot::Array_length());
517 builder.AddInstruction(
new StoreIndexedInstr(
520 target::Instance::ElementSizeFor(kArrayCid), kArrayCid,
523 Definition* null_def =
builder.AddNullDefinition();
528bool GraphIntrinsifier::Build_GrowableArraySetIndexedUnchecked(
529 FlowGraph* flow_graph) {
530 GraphEntryInstr* graph_entry = flow_graph->graph_entry();
531 auto normal_entry = graph_entry->normal_entry();
532 BlockBuilder
builder(flow_graph, normal_entry,
false);
534 Definition* array =
builder.AddParameter(0);
535 Definition* index =
builder.AddParameter(1);
538 VerifyParameterIsBoxed(&builder, 0);
539 VerifyParameterIsBoxed(&builder, 2);
541 index = CreateBoxedParameterIfNeeded(&builder, index, kUnboxedInt64, 1);
542 index = PrepareIndexedOp(flow_graph, &builder, array, index,
543 Slot::GrowableObjectArray_length());
545 Definition* backing_store =
builder.AddDefinition(
new LoadFieldInstr(
546 new Value(array), Slot::GrowableObjectArray_data(),
builder.Source()));
548 builder.AddInstruction(
new StoreIndexedInstr(
551 target::Instance::ElementSizeFor(kArrayCid), kArrayCid,
554 Definition* null_def =
builder.AddNullDefinition();
559bool GraphIntrinsifier::Build_GrowableArraySetData(FlowGraph* flow_graph) {
560 GraphEntryInstr* graph_entry = flow_graph->graph_entry();
561 auto normal_entry = graph_entry->normal_entry();
562 BlockBuilder
builder(flow_graph, normal_entry,
false);
564 Definition* growable_array =
builder.AddParameter(0);
566 Zone* zone = flow_graph->zone();
568 VerifyParameterIsBoxed(&builder, 0);
569 VerifyParameterIsBoxed(&builder, 1);
573 *value_check,
builder.Source()));
575 builder.AddInstruction(
new StoreFieldInstr(
576 Slot::GrowableObjectArray_data(),
new Value(growable_array),
579 Definition* null_def =
builder.AddNullDefinition();
584bool GraphIntrinsifier::Build_GrowableArraySetLength(FlowGraph* flow_graph) {
585 GraphEntryInstr* graph_entry = flow_graph->graph_entry();
586 auto normal_entry = graph_entry->normal_entry();
587 BlockBuilder
builder(flow_graph, normal_entry,
false);
589 Definition* growable_array =
builder.AddParameter(0);
592 VerifyParameterIsBoxed(&builder, 0);
593 VerifyParameterIsBoxed(&builder, 1);
597 builder.AddInstruction(
new StoreFieldInstr(
598 Slot::GrowableObjectArray_length(),
new Value(growable_array),
600 Definition* null_def =
builder.AddNullDefinition();
605static bool BuildUnarySmiOp(FlowGraph* flow_graph,
Token::Kind op_kind) {
606 ASSERT(!flow_graph->function().has_unboxed_return());
607 ASSERT(!flow_graph->function().is_unboxed_parameter_at(0));
608 GraphEntryInstr* graph_entry = flow_graph->graph_entry();
609 auto normal_entry = graph_entry->normal_entry();
610 BlockBuilder
builder(flow_graph, normal_entry,
false);
620bool GraphIntrinsifier::Build_Smi_bitNegate(FlowGraph* flow_graph) {
621 return BuildUnarySmiOp(flow_graph, Token::kBIT_NOT);
624bool GraphIntrinsifier::Build_Integer_negate(FlowGraph* flow_graph) {
625 return BuildUnarySmiOp(flow_graph, Token::kNEGATE);
628static bool BuildBinarySmiOp(FlowGraph* flow_graph,
Token::Kind op_kind) {
629 ASSERT(!flow_graph->function().has_unboxed_return());
630 ASSERT(!flow_graph->function().is_unboxed_parameter_at(0));
631 ASSERT(!flow_graph->function().is_unboxed_parameter_at(1));
632 GraphEntryInstr* graph_entry = flow_graph->graph_entry();
633 auto normal_entry = graph_entry->normal_entry();
634 BlockBuilder
builder(flow_graph, normal_entry,
false);
641 Definition*
result =
builder.AddDefinition(
new BinarySmiOpInstr(
647bool GraphIntrinsifier::Build_Integer_add(FlowGraph* flow_graph) {
648 return BuildBinarySmiOp(flow_graph, Token::kADD);
651bool GraphIntrinsifier::Build_Integer_sub(FlowGraph* flow_graph) {
652 return BuildBinarySmiOp(flow_graph, Token::kSUB);
655bool GraphIntrinsifier::Build_Integer_mul(FlowGraph* flow_graph) {
656 return BuildBinarySmiOp(flow_graph, Token::kMUL);
659bool GraphIntrinsifier::Build_Integer_mod(FlowGraph* flow_graph) {
660 return BuildBinarySmiOp(flow_graph, Token::kMOD);
663bool GraphIntrinsifier::Build_Integer_truncDivide(FlowGraph* flow_graph) {
664 return BuildBinarySmiOp(flow_graph, Token::kTRUNCDIV);
667bool GraphIntrinsifier::Build_Integer_bitAnd(FlowGraph* flow_graph) {
668 return BuildBinarySmiOp(flow_graph, Token::kBIT_AND);
671bool GraphIntrinsifier::Build_Integer_bitOr(FlowGraph* flow_graph) {
672 return BuildBinarySmiOp(flow_graph, Token::kBIT_OR);
675bool GraphIntrinsifier::Build_Integer_bitXor(FlowGraph* flow_graph) {
676 return BuildBinarySmiOp(flow_graph, Token::kBIT_XOR);
679bool GraphIntrinsifier::Build_Integer_sar(FlowGraph* flow_graph) {
680 return BuildBinarySmiOp(flow_graph, Token::kSHR);
683bool GraphIntrinsifier::Build_Integer_shr(FlowGraph* flow_graph) {
684 return BuildBinarySmiOp(flow_graph, Token::kUSHR);
687static Definition* ConvertOrUnboxDoubleParameter(BlockBuilder* builder,
692 if (
function.is_unboxed_double_parameter_at(index)) {
694 }
else if (
function.is_unboxed_integer_parameter_at(index)) {
695 if (compiler::target::kWordSize == 4) {
700 return builder->AddDefinition(to_double);
703 return builder->AddUnboxInstr(kUnboxedDouble, value, is_checked);
707bool GraphIntrinsifier::Build_DoubleFlipSignBit(FlowGraph* flow_graph) {
711 GraphEntryInstr* graph_entry = flow_graph->graph_entry();
712 auto normal_entry = graph_entry->normal_entry();
713 BlockBuilder
builder(flow_graph, normal_entry,
false);
715 Definition* receiver =
builder.AddParameter(0);
716 Definition* unboxed_value = ConvertOrUnboxDoubleParameter(
717 &builder, receiver, 0,
true);
718 if (unboxed_value ==
nullptr) {
721 Definition* unboxed_result =
builder.AddDefinition(
new UnaryDoubleOpInstr(
724 CreateBoxedResultIfNeeded(&builder, unboxed_result, kUnboxedDouble);
static bool left(const SkPoint &p0, const SkPoint &p1)
static bool right(const SkPoint &p0, const SkPoint &p1)
emscripten::val Uint32Array
emscripten::val Uint16Array
emscripten::val Float32Array
emscripten::val Uint8Array
static BoxInstr * Create(Representation from, Value *value)
static Cids * CreateMonomorphic(Zone *zone, intptr_t cid)
static void RunGraphIntrinsicPipeline(CompilerPassState *state)
static CompilerState & Current()
static constexpr intptr_t kNoOSRDeoptId
static constexpr intptr_t kNone
static bool SupportsUnboxedDoubles()
static bool SupportsUnboxedSimd128()
static bool ShouldPrint(const Function &function, uint8_t **compiler_pass_filter=nullptr)
static Representation ReturnRepresentationOf(const Function &function)
void RemoveRedefinitions(bool keep_checks=false)
void ComputeDominators(GrowableArray< BitVector * > *dominance_frontier)
bool HasOptionalParameters() const
~GraphIntrinsicCodeGenScope()
GraphIntrinsicCodeGenScope(FlowGraphCompiler *compiler)
const Function & function() const
static SimdOpInstr * Create(Kind kind, Value *left, Value *right, intptr_t deopt_id)
static Kind KindForOperator(MethodRecognizer::Kind kind)
static const Slot & GetLengthFieldForArrayCid(intptr_t array_cid)
static bool GraphIntrinsify(const ParsedFunction &parsed_function, FlowGraphCompiler *compiler)
#define THR_Print(format,...)
constexpr bool FLAG_support_il_printer
#define DECLARE_FLAG(type, name)
Dart_NativeFunction function
#define DEFINE_SIMD_ARRAY_SETTER_INTRINSIC(enum_name)
#define DEFINE_FLOAT_ARRAY_SETTER_INTRINSIC(enum_name)
#define DEFINE_ARRAY_SETTER_INTRINSIC(enum_name)
#define EMIT_CASE(Instruction, _)
bool IsTypedDataClassId(intptr_t index)
bool IsClampedTypedDataBaseClassId(intptr_t index)
static int8_t data[kExtLength]
static constexpr intptr_t kInvalidTryIndex
bool IsExternalTypedDataClassId(intptr_t index)
#define GRAPH_INTRINSICS_LIST(V)
static constexpr Representation NativeRepresentation(Representation rep)
static intptr_t BoxCid(Representation rep)
static constexpr bool IsUnboxedInteger(Representation rep)
static constexpr bool IsUnboxed(Representation rep)
static Representation RepresentationOfArrayElement(classid_t cid)