Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
flow_graph_test.cc
Go to the documentation of this file.
1// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
6
7#include <vector>
8
10#include "platform/utils.h"
16#include "vm/unit_test.h"
17
18namespace dart {
19
20#if defined(TARGET_ARCH_IS_64_BIT)
21ISOLATE_UNIT_TEST_CASE(FlowGraph_UnboxInt64Phi) {
22 using compiler::BlockBuilder;
23
24 CompilerState S(thread, /*is_aot=*/true, /*is_optimizing=*/true);
25
26 FlowGraphBuilderHelper H(/*num_parameters=*/1);
27 H.AddVariable("v0", AbstractType::ZoneHandle(Type::IntType()),
28 new CompileType(CompileType::Int()));
29
30 auto normal_entry = H.flow_graph()->graph_entry()->normal_entry();
31 auto loop_header = H.JoinEntry();
32 auto loop_body = H.TargetEntry();
33 auto loop_exit = H.TargetEntry();
34
35 Definition* v0;
36 PhiInstr* loop_var;
37 Definition* add1;
38
39 {
40 BlockBuilder builder(H.flow_graph(), normal_entry);
41 v0 = builder.AddParameter(0, kTagged);
42 builder.AddInstruction(new GotoInstr(loop_header, S.GetNextDeoptId()));
43 }
44
45 {
46 BlockBuilder builder(H.flow_graph(), loop_header);
47 loop_var = H.Phi(loop_header, {{normal_entry, v0}, {loop_body, &add1}});
48 builder.AddPhi(loop_var);
49 builder.AddBranch(new RelationalOpInstr(
50 InstructionSource(), Token::kLT, new Value(loop_var),
51 new Value(H.IntConstant(50)), kMintCid,
52 S.GetNextDeoptId(), Instruction::kNotSpeculative),
53 loop_body, loop_exit);
54 }
55
56 {
57 BlockBuilder builder(H.flow_graph(), loop_body);
58 add1 = builder.AddDefinition(new BinaryInt64OpInstr(
59 Token::kADD, new Value(loop_var), new Value(H.IntConstant(1)),
60 S.GetNextDeoptId(), Instruction::kNotSpeculative));
61 builder.AddInstruction(new GotoInstr(loop_header, S.GetNextDeoptId()));
62 }
63
64 {
65 BlockBuilder builder(H.flow_graph(), loop_exit);
66 builder.AddReturn(new Value(loop_var));
67 }
68
69 H.FinishGraph();
70
71 FlowGraphTypePropagator::Propagate(H.flow_graph());
72 H.flow_graph()->SelectRepresentations();
73
74 EXPECT_PROPERTY(loop_var, it.representation() == kUnboxedInt64);
75}
76#endif // defined(TARGET_ARCH_IS_64_BIT)
77
78ISOLATE_UNIT_TEST_CASE(FlowGraph_LateVariablePhiUnboxing) {
80
81 CompilerState S(thread, /*is_aot=*/true, /*is_optimizing=*/true);
83
84 auto normal_entry = H.flow_graph()->graph_entry()->normal_entry();
85 auto loop_header = H.JoinEntry();
86 auto loop_body = H.TargetEntry();
87 auto loop_exit = H.TargetEntry();
88
89 ConstantInstr* sentinel = H.flow_graph()->GetConstant(Object::sentinel());
90
91 PhiInstr* loop_var;
92 PhiInstr* late_var;
93 Definition* add1;
94
95 {
96 BlockBuilder builder(H.flow_graph(), normal_entry);
97 builder.AddInstruction(new GotoInstr(loop_header, S.GetNextDeoptId()));
98 }
99
100 {
101 BlockBuilder builder(H.flow_graph(), loop_header);
102 loop_var = H.Phi(loop_header,
103 {{normal_entry, H.IntConstant(0)}, {loop_body, &add1}});
104 builder.AddPhi(loop_var);
105 loop_var->UpdateType(CompileType::Int());
109 late_var =
110 H.Phi(loop_header, {{normal_entry, sentinel}, {loop_body, &add1}});
111 builder.AddPhi(late_var);
112 builder.AddBranch(new RelationalOpInstr(
113 InstructionSource(), Token::kLT, new Value(loop_var),
114 new Value(H.IntConstant(10)), kMintCid,
115 S.GetNextDeoptId(), Instruction::kNotSpeculative),
116 loop_body, loop_exit);
117 }
118
119 {
120 BlockBuilder builder(H.flow_graph(), loop_body);
121 add1 = builder.AddDefinition(new BinaryInt64OpInstr(
122 Token::kADD, new Value(loop_var), new Value(H.IntConstant(1)),
123 S.GetNextDeoptId(), Instruction::kNotSpeculative));
124 builder.AddInstruction(new GotoInstr(loop_header, S.GetNextDeoptId()));
125 }
126
127 {
128 BlockBuilder builder(H.flow_graph(), loop_exit);
129 builder.AddReturn(new Value(late_var));
130 }
131
132 H.FinishGraph();
133
134 FlowGraphTypePropagator::Propagate(H.flow_graph());
135 H.flow_graph()->SelectRepresentations();
136
137#if defined(TARGET_ARCH_IS_64_BIT)
138 EXPECT_PROPERTY(loop_var, it.representation() == kUnboxedInt64);
139#endif
140 EXPECT_PROPERTY(late_var, it.representation() == kTagged);
141}
142
143ISOLATE_UNIT_TEST_CASE(FlowGraph_UnboxedFloatPhi) {
145
146 CompilerState S(thread, /*is_aot=*/true, /*is_optimizing=*/true);
148
149 auto normal_entry = H.flow_graph()->graph_entry()->normal_entry();
150 auto then_body = H.TargetEntry();
151 auto else_body = H.TargetEntry();
152 auto join_exit = H.JoinEntry();
153
154 PhiInstr* phi;
155 Definition* double_to_float_1;
156 Definition* double_to_float_2;
157
158 {
159 BlockBuilder builder(H.flow_graph(), normal_entry);
160 builder.AddBranch(
162 InstructionSource(), Token::kEQ_STRICT, new Value(H.IntConstant(1)),
163 new Value(H.IntConstant(1)),
164 /*needs_number_check=*/false, S.GetNextDeoptId()),
165 then_body, else_body);
166 }
167
168 {
169 BlockBuilder builder(H.flow_graph(), then_body);
170 double_to_float_1 = builder.AddDefinition(new DoubleToFloatInstr(
171 new Value(H.DoubleConstant(1)), S.GetNextDeoptId(),
173 builder.AddInstruction(new GotoInstr(join_exit, S.GetNextDeoptId()));
174 }
175
176 {
177 BlockBuilder builder(H.flow_graph(), else_body);
178 double_to_float_2 = builder.AddDefinition(new DoubleToFloatInstr(
179 new Value(H.DoubleConstant(2)), S.GetNextDeoptId(),
181 builder.AddInstruction(new GotoInstr(join_exit, S.GetNextDeoptId()));
182 }
183
184 {
185 BlockBuilder builder(H.flow_graph(), join_exit);
186 phi = new PhiInstr(join_exit, 3);
187 phi->SetInputAt(0, new Value(double_to_float_1));
188 phi->SetInputAt(1, new Value(double_to_float_2));
189 phi->SetInputAt(2, new Value(phi));
190 builder.AddPhi(phi);
191 builder.AddReturn(new Value(phi));
192 }
193 H.FinishGraph();
194
195 FlowGraphTypePropagator::Propagate(H.flow_graph());
196 H.flow_graph()->SelectRepresentations();
197
198 EXPECT_PROPERTY(phi, it.representation() == kUnboxedFloat);
199}
200
201void TestLargeFrame(const char* type,
202 const char* zero,
203 const char* one,
204 const char* main) {
205 SetFlagScope<int> sfs(&FLAG_optimization_counter_threshold, 1000);
206 TextBuffer printer(256 * KB);
207
208 intptr_t num_locals = 2000;
209 printer.Printf("import 'dart:typed_data';\n");
210 printer.Printf("@pragma('vm:never-inline')\n");
211 printer.Printf("%s one() { return %s; }\n", type, one);
212 printer.Printf("@pragma('vm:never-inline')\n");
213 printer.Printf("%s largeFrame(int n) {\n", type);
214 for (intptr_t i = 0; i < num_locals; i++) {
215 printer.Printf(" %s local%" Pd " = %s;\n", type, i, zero);
216 }
217 printer.Printf(" for (int i = 0; i < n; i++) {\n");
218 for (intptr_t i = 0; i < num_locals; i++) {
219 printer.Printf(" local%" Pd " += one();\n", i);
220 }
221 printer.Printf(" }\n");
222 printer.Printf(" %s sum = %s;\n", type, zero);
223 for (intptr_t i = 0; i < num_locals; i++) {
224 printer.Printf(" sum += local%" Pd ";\n", i);
225 }
226 printer.Printf(" return sum;\n");
227 printer.Printf("}\n");
228
229 printer.AddString(main);
230
231 const auto& root_library = Library::Handle(LoadTestScript(printer.buffer()));
232 Invoke(root_library, "main");
233}
234
235ISOLATE_UNIT_TEST_CASE(FlowGraph_LargeFrame_Int) {
236 TestLargeFrame("int", "0", "1",
237 "main() {\n"
238 " for (var i = 0; i < 100; i++) {\n"
239 " var r = largeFrame(1);\n"
240 " if (r != 2000) throw r;\n"
241 " }\n"
242 " return 'Okay';\n"
243 "}\n");
244}
245
246ISOLATE_UNIT_TEST_CASE(FlowGraph_LargeFrame_Double) {
247 TestLargeFrame("double", "0.0", "1.0",
248 "main() {\n"
249 " for (var i = 0; i < 100; i++) {\n"
250 " var r = largeFrame(1);\n"
251 " if (r != 2000.0) throw r;\n"
252 " }\n"
253 " return 'Okay';\n"
254 "}\n");
255}
256
257ISOLATE_UNIT_TEST_CASE(FlowGraph_LargeFrame_Int32x4) {
258 TestLargeFrame("Int32x4", "Int32x4(0, 0, 0, 0)", "Int32x4(1, 2, 3, 4)",
259 "main() {\n"
260 " for (var i = 0; i < 100; i++) {\n"
261 " var r = largeFrame(1);\n"
262 " if (r.x != 2000) throw r;\n"
263 " if (r.y != 4000) throw r;\n"
264 " if (r.z != 6000) throw r;\n"
265 " if (r.w != 8000) throw r;\n"
266 " }\n"
267 " return 'Okay';\n"
268 "}\n");
269}
270
271ISOLATE_UNIT_TEST_CASE(FlowGraph_LargeFrame_Float32x4) {
272 TestLargeFrame("Float32x4", "Float32x4(0.0, 0.0, 0.0, 0.0)",
273 "Float32x4(1.0, 2.0, 3.0, 4.0)",
274 "main() {\n"
275 " for (var i = 0; i < 100; i++) {\n"
276 " var r = largeFrame(1);\n"
277 " if (r.x != 2000.0) throw r;\n"
278 " if (r.y != 4000.0) throw r;\n"
279 " if (r.z != 6000.0) throw r;\n"
280 " if (r.w != 8000.0) throw r;\n"
281 " }\n"
282 " return 'Okay';\n"
283 "}\n");
284}
285
286ISOLATE_UNIT_TEST_CASE(FlowGraph_LargeFrame_Float64x2) {
287 TestLargeFrame("Float64x2", "Float64x2(0.0, 0.0)", "Float64x2(1.0, 2.0)",
288 "main() {\n"
289 " for (var i = 0; i < 100; i++) {\n"
290 " var r = largeFrame(1);\n"
291 " if (r.x != 2000.0) throw r;\n"
292 " if (r.y != 4000.0) throw r;\n"
293 " }\n"
294 " return 'Okay';\n"
295 "}\n");
296}
297
298ISOLATE_UNIT_TEST_CASE(FlowGraph_PhiUnboxingHeuristic_Double) {
300 return;
301 }
302
303 const char* kScript = R"(
304 double foo(double sum, int n) {
305 if (sum == null) return 0.0;
306 for (int i = 0; i < n; i++) {
307 sum += 1.0;
308 }
309 return sum;
310 }
311 main() {
312 foo(0.0, 10);
313 }
314 )";
315
316 const auto& root_library = Library::Handle(LoadTestScript(kScript));
317 const auto& function = Function::Handle(GetFunction(root_library, "foo"));
318
319 Invoke(root_library, "main");
320
322 FlowGraph* flow_graph = pipeline.RunPasses({});
323
324 auto entry = flow_graph->graph_entry()->normal_entry();
325 ILMatcher cursor(flow_graph, entry, /*trace=*/true,
327
328 RELEASE_ASSERT(cursor.TryMatch({
329 kMatchAndMoveFunctionEntry,
330 }));
331 RELEASE_ASSERT(cursor.TryMatch({
332 kMatchAndMoveUnbox, // outside of loop
333 kMatchAndMoveCheckSmi,
334 kMoveGlob,
335
336 // Loop header
337 kMatchAndMoveJoinEntry,
338 kMatchAndMoveCheckStackOverflow,
339 kMatchAndMoveBranchTrue,
340
341 // Loop body
342 kMatchAndMoveTargetEntry,
343 kMatchAndMoveBinaryDoubleOp,
344 kMatchAndMoveBinarySmiOp,
345 kMatchAndMoveGoto,
346
347 // Loop header, again
348 kMatchAndMoveJoinEntry,
349 kMatchAndMoveCheckStackOverflow,
350 kMatchAndMoveBranchFalse,
351
352 // After loop
353 kMatchAndMoveTargetEntry,
354 kMatchAndMoveBox,
355 kMatchDartReturn,
356 }));
357}
358
359static void TestPhiUnboxingHeuristicSimd(const char* script) {
361 return;
362 }
363
364 const auto& root_library = Library::Handle(LoadTestScript(script));
365 const auto& function = Function::Handle(GetFunction(root_library, "foo"));
366
367 Invoke(root_library, "main");
368
370 FlowGraph* flow_graph = pipeline.RunPasses({});
371
372 auto entry = flow_graph->graph_entry()->normal_entry();
373 ILMatcher cursor(flow_graph, entry, /*trace=*/true,
375
376 RELEASE_ASSERT(cursor.TryMatch({
377 kMatchAndMoveFunctionEntry,
378 }));
379 RELEASE_ASSERT(cursor.TryMatch({
380 kMatchAndMoveUnbox, // outside of loop
381 kMatchAndMoveCheckSmi,
382 kMoveGlob,
383
384 // Loop header
385 kMatchAndMoveJoinEntry,
386 kMatchAndMoveCheckStackOverflow,
387 kMatchAndMoveBranchTrue,
388
389 // Loop body
390 kMatchAndMoveTargetEntry,
391 kMatchAndMoveSimdOp,
392 kMatchAndMoveBinarySmiOp,
393 kMatchAndMoveGoto,
394
395 // Loop header, again
396 kMatchAndMoveJoinEntry,
397 kMatchAndMoveCheckStackOverflow,
398 kMatchAndMoveBranchFalse,
399
400 // After loop
401 kMatchAndMoveTargetEntry,
402 kMatchAndMoveBox,
403 kMatchDartReturn,
404 }));
405}
406
407ISOLATE_UNIT_TEST_CASE(FlowGraph_PhiUnboxingHeuristic_Float32x4) {
408 const char* kScript = R"(
409 import 'dart:typed_data';
410 Float32x4 foo(Float32x4 sum, int n) {
411 if (sum == null) return Float32x4(0.0, 0.0, 0.0, 0.0);
412 for (int i = 0; i < n; i++) {
413 sum += Float32x4(1.0, 2.0, 3.0, 4.0);
414 }
415 return sum;
416 }
417 main() {
418 foo(Float32x4(0.0, 0.0, 0.0, 0.0), 10);
419 }
420 )";
422}
423
424ISOLATE_UNIT_TEST_CASE(FlowGraph_PhiUnboxingHeuristic_Float64x2) {
425 const char* kScript = R"(
426 import 'dart:typed_data';
427 Float64x2 foo(Float64x2 sum, int n) {
428 if (sum == null) return Float64x2(0.0, 0.0);
429 for (int i = 0; i < n; i++) {
430 sum += Float64x2(1.0, 2.0);
431 }
432 return sum;
433 }
434 main() {
435 foo(Float64x2(0.0, 0.0), 10);
436 }
437 )";
439}
440
441ISOLATE_UNIT_TEST_CASE(FlowGraph_PhiUnboxingHeuristic_Int32x4) {
442 const char* kScript = R"(
443 import 'dart:typed_data';
444 Int32x4 foo(Int32x4 sum, int n) {
445 if (sum == null) return Int32x4(0, 0, 0, 0);
446 for (int i = 0; i < n; i++) {
447 sum += Int32x4(1, 2, 3, 4);
448 }
449 return sum;
450 }
451 main() {
452 foo(Int32x4(0, 0, 0, 0), 10);
453 }
454 )";
456}
457
458} // namespace dart
#define RELEASE_ASSERT(cond)
Definition assert.h:327
void AddString(const char *s)
intptr_t Printf(const char *format,...) PRINTF_ATTRIBUTE(2
char * buffer() const
Definition text_buffer.h:35
static constexpr bool kCanBeSentinel
static constexpr bool kCannotBeNull
static CompileType Int()
static CompileType FromAbstractType(const AbstractType &type, bool can_be_null, bool can_be_sentinel)
PRINT_OPERANDS_TO_SUPPORT PRINT_TO_SUPPORT bool UpdateType(CompileType new_type)
Definition il.h:2535
static bool SupportsUnboxedDoubles()
static bool SupportsUnboxedSimd128()
GraphEntryInstr * graph_entry() const
Definition flow_graph.h:268
FunctionEntryInstr * normal_entry() const
Definition il.h:1986
bool TryMatch(std::initializer_list< MatchCode > match_codes, MatchOpCode insert_before=kInvalidMatchOpCode)
@ kNotSpeculative
Definition il.h:969
void SetInputAt(intptr_t i, Value *value)
Definition il.h:1008
static Object & Handle()
Definition object.h:407
static Object & ZoneHandle()
Definition object.h:419
virtual Representation representation() const
Definition il.h:2817
FlowGraph * RunPasses(std::initializer_list< CompilerPass::Id > passes)
static TypePtr IntType()
Definition object.cc:21886
#define H
Dart_NativeFunction function
Definition fuchsia.cc:51
#define EXPECT_PROPERTY(entity, property)
LibraryPtr LoadTestScript(const char *script, Dart_NativeEntryResolver resolver, const char *lib_uri)
void TestLargeFrame(const char *type, const char *zero, const char *one, const char *main)
ObjectPtr Invoke(const Library &lib, const char *name)
FunctionPtr GetFunction(const Library &lib, const char *name)
constexpr intptr_t KB
Definition globals.h:528
static void TestPhiUnboxingHeuristicSimd(const char *script)
Definition main.py:1
#define Pd
Definition globals.h:408
Definition SkMD5.cpp:130
#define ISOLATE_UNIT_TEST_CASE(name)
Definition unit_test.h:64