26using compiler::BlockBuilder;
34 auto normal_entry =
H.flow_graph()->graph_entry()->normal_entry();
48 auto b2 =
H.TargetEntry();
49 auto b3 =
H.TargetEntry();
53 v0 = builder.AddParameter(0, kTagged);
58 false,
S.GetNextDeoptId()),
64 builder.AddReturn(
new Value(v0));
69 builder.AddReturn(
new Value(v0));
74 FlowGraphTypePropagator::Propagate(
H.flow_graph());
82 auto b2_value = b2->last_instruction()->AsDartReturn()->value();
83 EXPECT(b2_value->Type()->IsNullableInt());
88 auto b3_value = b3->last_instruction()->AsDartReturn()->value();
89 EXPECT(b3_value->Type()->IsInt());
90 EXPECT(b3_value->definition()->IsRedefinition());
91 EXPECT(b3_value->definition()->GetBlock() == b3);
95 TypePropagator_RedefinitionAfterStrictCompareWithLoadClassId) {
114 auto b1 =
H.flow_graph()->graph_entry()->normal_entry();
115 auto b2 =
H.TargetEntry();
116 auto b3 =
H.TargetEntry();
120 v0 = builder.AddParameter(0, kTagged);
125 new Value(
H.IntConstant(kDoubleCid)),
126 false,
S.GetNextDeoptId()),
132 builder.AddReturn(
new Value(v0));
137 builder.AddReturn(
new Value(v0));
142 FlowGraphTypePropagator::Propagate(
H.flow_graph());
147 auto b3_value = b3->last_instruction()->AsDartReturn()->value();
153 auto b2_value = b2->last_instruction()->AsDartReturn()->value();
162 const Class& object_class =
163 Class::Handle(thread->isolate_group()->object_store()->object_class());
168 UntaggedFunction::kRegularFunction,
173 true, object_class, TokenPosition::kNoSource));
182 false, object_class, Object::dynamic_type(),
183 TokenPosition::kNoSource, TokenPosition::kNoSource));
186 thread->isolate_group()->program_lock());
187 thread->isolate_group()->RegisterStaticField(field,
Object::Handle());
212 auto b1 =
H.flow_graph()->graph_entry()->normal_entry();
213 auto b2 =
H.TargetEntry();
214 auto b3 =
H.TargetEntry();
215 auto b4 =
H.JoinEntry();
219 v0 = builder.AddParameter(0, kTagged);
222 new Value(
H.IntConstant(1)),
223 false,
S.GetNextDeoptId()),
229 v2 = builder.AddDefinition(
232 Array::empty_array(),
234 0, ICData::RebindRule::kStatic));
235 builder.AddInstruction(
new GotoInstr(b4,
S.GetNextDeoptId()));
240 builder.AddInstruction(
new GotoInstr(b4,
S.GetNextDeoptId()));
245 v3 =
H.Phi(b4, {{b2,
v2}, {b3,
H.IntConstant(0)}});
247 builder.AddReturn(
new Value(v3));
251 FlowGraphTypePropagator::Propagate(
H.flow_graph());
258 v2->ReplaceUsesWith(
v4);
259 v2->RemoveFromGraph();
261 FlowGraphTypePropagator::Propagate(
H.flow_graph());
300 auto b1 =
H.flow_graph()->graph_entry()->normal_entry();
301 auto b2 =
H.TargetEntry();
302 auto b3 =
H.TargetEntry();
303 auto b4 =
H.TargetEntry();
304 auto b5 =
H.JoinEntry();
305 auto b6 =
H.TargetEntry();
306 auto b7 =
H.JoinEntry();
310 v0 = builder.AddParameter(0, kTagged);
313 new Value(
H.IntConstant(1)),
314 false,
S.GetNextDeoptId()),
322 new Value(
H.IntConstant(2)),
323 false,
S.GetNextDeoptId()),
329 builder.AddInstruction(
new GotoInstr(b5,
S.GetNextDeoptId()));
334 builder.AddInstruction(
new GotoInstr(b5,
S.GetNextDeoptId()));
339 v3 =
H.Phi(b5, {{b3,
H.IntConstant(42)}, {b4,
H.IntConstant(24)}});
341 builder.AddInstruction(
new GotoInstr(b7,
S.GetNextDeoptId()));
346 builder.AddInstruction(
new GotoInstr(b7,
S.GetNextDeoptId()));
351 v5 =
H.Phi(b7, {{b5, v3}, {b6,
H.DoubleConstant(1.0)}});
359 FlowGraphTypePropagator::Propagate(
H.flow_graph());
371 for (intptr_t i = 0; i < v3->
InputCount(); i++) {
376 H.flow_graph()->InsertBefore(
379 input->BindTo(unbox);
384 H.flow_graph()->InsertBefore(b4->last_instruction(), box,
nullptr,
389 FlowGraphTypePropagator::Propagate(
H.flow_graph());
411 NumBound extends num,
412 ComparableBound extends Comparable,
413 StringBound extends String> {
414 // Simple instantiated types.
415 @pragma('vm-test:can-be-smi') %s int t1;
416 @pragma('vm-test:can-be-smi') %s num t2;
417 @pragma('vm-test:can-be-smi') %s Object t3;
421 @pragma('vm-test:can-be-smi') %s NoBound tp1;
422 @pragma('vm-test:can-be-smi') %s NumBound tp2;
423 @pragma('vm-test:can-be-smi') %s ComparableBound tp3;
426 // Comparable<T> instantiations.
427 @pragma('vm-test:can-be-smi') %s Comparable c1;
428 %s Comparable<String> c2;
429 @pragma('vm-test:can-be-smi') %s Comparable<num> c3;
430 %s Comparable<int> c4; // int is not a subtype of Comparable<int>.
431 @pragma('vm-test:can-be-smi') %s Comparable<NoBound> c5;
432 @pragma('vm-test:can-be-smi') %s Comparable<NumBound> c6;
433 @pragma('vm-test:can-be-smi') %s Comparable<ComparableBound> c7;
434 %s Comparable<StringBound> c8;
436 // FutureOr<T> instantiations.
437 @pragma('vm-test:can-be-smi') %s FutureOr fo1;
438 %s FutureOr<String> fo2;
439 @pragma('vm-test:can-be-smi') %s FutureOr<num> fo3;
440 @pragma('vm-test:can-be-smi') %s FutureOr<int> fo4;
441 @pragma('vm-test:can-be-smi') %s FutureOr<NoBound> fo5;
442 @pragma('vm-test:can-be-smi') %s FutureOr<NumBound> fo6;
443 @pragma('vm-test:can-be-smi') %s FutureOr<ComparableBound> fo7;
444 %s FutureOr<StringBound> fo8;
446 // Other generic classes.
451 late_tag, late_tag, late_tag, late_tag, late_tag, late_tag,
452 late_tag, late_tag, late_tag, late_tag, late_tag, late_tag,
453 late_tag, late_tag, late_tag, late_tag, late_tag, late_tag,
454 late_tag, late_tag, late_tag, late_tag, late_tag, late_tag,
460 const auto& pragma_can_be_smi =
462 auto expected_can_be_smi = [&](
const Field& f) {
464 return lib.FindPragma(thread,
false, f, pragma_can_be_smi,
469 const auto& err =
Error::Handle(cls.EnsureIsFinalized(thread));
475 for (intptr_t i = 0; i < fields.Length(); i++) {
476 field ^= fields.At(i);
481 if (compile_type.CanBeSmi() != expected_can_be_smi(field)) {
483 .
Fail(
"expected that CanBeSmi() returns %s for compile type %s\n",
484 expected_can_be_smi(field) ?
"true" :
"false",
485 compile_type.ToCString());
499 auto normal_entry =
H.flow_graph()->graph_entry()->normal_entry();
512 Definition* v0 = builder.AddParameter(0, kTagged);
513 auto null_value = builder.AddNullDefinition();
518 new Value(null_value),
new Value(null_value), Symbols::Value(),
519 S.GetNextDeoptId()));
522 builder.AddReturn(
new Value(v0));
527 H.flow_graph()->EliminateEnvironments();
528 FlowGraphTypePropagator::Propagate(
H.flow_graph());
531#if defined(DART_PRECOMPILER)
537 const char* kScript = R
"(
538 const y = 0xDEADBEEF;
539 final int x = int.parse('0xFEEDFEED');
541 void main(List<String> args) {
551 FlowGraph* flow_graph = pipeline.RunPasses({});
553 auto entry = flow_graph->graph_entry()->normal_entry();
554 ILMatcher cursor(flow_graph, entry,
true,
557 Instruction*
load =
nullptr;
561 {kMatchAndMoveLoadStaticField, &load},
562 kMatchAndMoveMoveArgument,
563 kMatchAndMoveStaticCall,
564 kMatchAndMoveUnboxInt64,
565 kMatchAndMoveBinaryInt64Op,
566 kMatchAndMoveBoxInt64,
567 kMatchAndMoveMoveArgument,
568 kMatchAndMoveStaticCall,
576 const char* kScript = R
"(
579 Zone* const Z = Thread::Current()->zone();
580 const auto& root_library = Library::CheckedHandle(
Z,
LoadTestScript(kScript));
581 const auto& toplevel = Class::Handle(
Z, root_library.toplevel_class());
582 const auto& field_x = Field::Handle(
583 Z, toplevel.LookupStaticField(String::Handle(
Z, String::New(
"x"))));
585 using compiler::BlockBuilder;
586 CompilerState
S(thread,
false,
true);
587 FlowGraphBuilderHelper
H;
608 Definition*
v2 =
H.IntConstant(3);
612 auto b1 =
H.flow_graph()->graph_entry()->normal_entry();
613 auto b2 =
H.TargetEntry();
614 auto b3 =
H.TargetEntry();
615 auto b4 =
H.JoinEntry();
618 BlockBuilder
builder(
H.flow_graph(), b1);
619 v3 =
builder.AddDefinition(
new LoadStaticFieldInstr(
621 false,
S.GetNextDeoptId()));
622 auto v5 =
builder.AddDefinition(
new ConstantInstr(Object::sentinel()));
623 builder.AddBranch(
new StrictCompareInstr(
624 {}, Token::kEQ_STRICT,
new Value(v3),
new Value(v5),
625 false,
S.GetNextDeoptId()),
630 BlockBuilder
builder(
H.flow_graph(), b2);
631 builder.AddInstruction(
new GotoInstr(b4,
S.GetNextDeoptId()));
635 BlockBuilder
builder(
H.flow_graph(), b3);
636 v7 =
builder.AddDefinition(
new RedefinitionInstr(
new Value(v3)));
637 CompileType int_type =
638 CompileType::FromAbstractType(Type::Handle(Type::IntType()),
641 v7->AsRedefinition()->set_constrained_type(
new CompileType(int_type));
642 builder.AddInstruction(
new GotoInstr(b4,
S.GetNextDeoptId()));
646 BlockBuilder
builder(
H.flow_graph(), b4);
647 v9 =
H.Phi(b4, {{b2,
v2}, {b3, v7}});
654 FlowGraphPrinter::PrintGraph(
"Before TypePropagator",
H.flow_graph());
655 FlowGraphTypePropagator::Propagate(
H.flow_graph());
656 FlowGraphPrinter::PrintGraph(
"After TypePropagator",
H.flow_graph());
658 auto& blocks =
H.flow_graph()->reverse_postorder();
659 EXPECT_EQ(5, blocks.length());
673 it.can_be_sentinel());
682 !it.can_be_sentinel());
690 EXPECT_PROPERTY(blocks[4]->AsJoinEntry()->phis()->At(0), it.HasType());
692 !it.can_be_sentinel());
700 const char* kScript = R
"(
701 @pragma('vm:never-inline')
702 (int, {String foo}) bar() => (42, foo: 'hi');
703 @pragma('vm:never-inline')
713 const auto& root_library = Library::Handle(
LoadTestScript(kScript));
714 Invoke(root_library,
"main");
721 ILMatcher cursor(flow_graph, entry,
true,
722 ParallelMovesHandling::kSkip);
729 kMatchAndMoveStaticCall,
730 {kMatchAndMoveLoadField, &load1},
731 kMatchAndMoveCheckSmi,
732 kMatchAndMoveBinarySmiOp,
733 kMatchAndMoveMoveArgument,
734 kMatchAndMoveStaticCall,
735 {kMatchAndMoveLoadField, &load2},
736 kMatchAndMoveMoveArgument,
737 kMatchAndMoveStaticCall,
static float next(float f)
static SkV4 v4(SkV3 v, SkScalar w)
#define RELEASE_ASSERT(cond)
bool IsObjectType() const
bool IsDynamicType() const
Instruction * last_instruction() const
static constexpr bool kCannotBeSentinel
static constexpr bool kCanBeNull
static CompileType FromAbstractType(const AbstractType &type, bool can_be_null, bool can_be_sentinel)
const AbstractType * ToAbstractType()
void ReplaceUsesWith(Definition *other)
void Fail(const char *format,...) const PRINTF_ATTRIBUTE(2
GraphEntryInstr * graph_entry() const
void set_result_type(const AbstractType &value) const
static FunctionTypePtr New(intptr_t num_parent_type_arguments=0, Nullability nullability=Nullability::kLegacy, Heap::Space space=Heap::kOld)
static FunctionPtr New(const FunctionType &signature, const String &name, UntaggedFunction::Kind kind, bool is_static, bool is_const, bool is_abstract, bool is_external, bool is_native, const Object &owner, TokenPosition token_pos, Heap::Space space=Heap::kOld)
FunctionEntryInstr * normal_entry() const
bool TryMatch(std::initializer_list< MatchCode > match_codes, MatchOpCode insert_before=kInvalidMatchOpCode)
virtual BlockEntryInstr * PredecessorAt(intptr_t index) const
static char * SCreate(Zone *zone, const char *format,...) PRINTF_ATTRIBUTE(2
static Object & ZoneHandle()
JoinEntryInstr * block() const
virtual void set_representation(Representation r)
static StringPtr New(Thread *thread, const char *cstr)
static const char * LateTag()
FlowGraph * RunPasses(std::initializer_list< CompilerPass::Id > passes)
static TypePtr DynamicType()
std::unique_ptr< char, decltype(std::free) * > CStringUniquePtr
intptr_t InputCount() const
Value * InputAt(intptr_t i) const
Dart_NativeFunction function
#define EXPECT_PROPERTY(entity, property)
LibraryPtr LoadTestScript(const char *script, Dart_NativeEntryResolver resolver, const char *lib_uri)
GrowableArray< Value * > InputsArray
ObjectPtr Invoke(const Library &lib, const char *name)
FunctionPtr GetFunction(const Library &lib, const char *name)
ClassPtr GetClass(const Library &lib, const char *name)
#define ISOLATE_UNIT_TEST_CASE(name)