Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(100)

Side by Side Diff: runtime/vm/aot_optimizer.cc

Issue 1714743002: VM: Separate precompilation-specific code, make flags const. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: addressed comments Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/flow_graph_optimizer.h" 5 #include "vm/aot_optimizer.h"
6 6
7 #include "vm/bit_vector.h" 7 #include "vm/bit_vector.h"
8 #include "vm/branch_optimizer.h" 8 #include "vm/branch_optimizer.h"
9 #include "vm/cha.h" 9 #include "vm/cha.h"
10 #include "vm/compiler.h" 10 #include "vm/compiler.h"
11 #include "vm/cpu.h" 11 #include "vm/cpu.h"
12 #include "vm/dart_entry.h" 12 #include "vm/dart_entry.h"
13 #include "vm/exceptions.h" 13 #include "vm/exceptions.h"
14 #include "vm/flow_graph_builder.h" 14 #include "vm/flow_graph_builder.h"
15 #include "vm/flow_graph_compiler.h" 15 #include "vm/flow_graph_compiler.h"
16 #include "vm/flow_graph_inliner.h" 16 #include "vm/flow_graph_inliner.h"
17 #include "vm/flow_graph_range_analysis.h" 17 #include "vm/flow_graph_range_analysis.h"
18 #include "vm/hash_map.h" 18 #include "vm/hash_map.h"
19 #include "vm/il_printer.h" 19 #include "vm/il_printer.h"
20 #include "vm/intermediate_language.h" 20 #include "vm/intermediate_language.h"
21 #include "vm/object.h"
21 #include "vm/object_store.h" 22 #include "vm/object_store.h"
22 #include "vm/parser.h" 23 #include "vm/parser.h"
23 #include "vm/precompiler.h" 24 #include "vm/precompiler.h"
24 #include "vm/resolver.h" 25 #include "vm/resolver.h"
25 #include "vm/scopes.h" 26 #include "vm/scopes.h"
26 #include "vm/stack_frame.h" 27 #include "vm/stack_frame.h"
27 #include "vm/symbols.h" 28 #include "vm/symbols.h"
28 29
29 namespace dart { 30 namespace dart {
30 31
31 DEFINE_FLAG(int, getter_setter_ratio, 13,
32 "Ratio of getter/setter usage used for double field unboxing heuristics");
33 DEFINE_FLAG(bool, guess_icdata_cid, true,
34 "Artificially create type feedback for arithmetic etc. operations"
35 " by guessing the other unknown argument cid");
36 DEFINE_FLAG(int, max_polymorphic_checks, 4,
37 "Maximum number of polymorphic check, otherwise it is megamorphic.");
38 DEFINE_FLAG(int, max_equality_polymorphic_checks, 32,
39 "Maximum number of polymorphic checks in equality operator,"
40 " otherwise use megamorphic dispatch.");
41 DEFINE_FLAG(bool, merge_sin_cos, false, "Merge sin/cos into sincos");
42 DEFINE_FLAG(bool, trace_optimization, false, "Print optimization details.");
43 DEFINE_FLAG(bool, truncating_left_shift, true,
44 "Optimize left shift to truncate if possible");
45 DEFINE_FLAG(bool, use_cha_deopt, true,
46 "Use class hierarchy analysis even if it can cause deoptimization.");
47
48 DECLARE_FLAG(bool, precompilation); 32 DECLARE_FLAG(bool, precompilation);
49 DECLARE_FLAG(bool, polymorphic_with_deopt);
50 DECLARE_FLAG(bool, trace_cha);
51 DECLARE_FLAG(bool, trace_field_guards);
52 33
53 // Quick access to the current isolate and zone. 34 // Quick access to the current isolate and zone.
54 #define I (isolate()) 35 #define I (isolate())
55 #define Z (zone()) 36 #define Z (zone())
56 37
57 static bool ShouldInlineSimd() { 38 static bool ShouldInlineSimd() {
58 return FlowGraphCompiler::SupportsUnboxedSimd128(); 39 return FlowGraphCompiler::SupportsUnboxedSimd128();
59 } 40 }
60 41
61 42
62 static bool CanUnboxDouble() { 43 static bool CanUnboxDouble() {
63 return FlowGraphCompiler::SupportsUnboxedDoubles(); 44 return FlowGraphCompiler::SupportsUnboxedDoubles();
64 } 45 }
65 46
66 47
67 static bool CanConvertUnboxedMintToDouble() { 48 static bool CanConvertUnboxedMintToDouble() {
68 return FlowGraphCompiler::CanConvertUnboxedMintToDouble(); 49 return FlowGraphCompiler::CanConvertUnboxedMintToDouble();
69 } 50 }
70 51
71 52
72 // Optimize instance calls using ICData. 53 // Optimize instance calls using ICData.
73 void FlowGraphOptimizer::ApplyICData() { 54 void AotOptimizer::ApplyICData() {
74 VisitBlocks(); 55 VisitBlocks();
75 } 56 }
76 57
77 58
78 void FlowGraphOptimizer::PopulateWithICData() { 59 void AotOptimizer::PopulateWithICData() {
79 ASSERT(current_iterator_ == NULL); 60 ASSERT(current_iterator_ == NULL);
80 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); 61 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator();
81 !block_it.Done(); 62 !block_it.Done();
82 block_it.Advance()) { 63 block_it.Advance()) {
83 ForwardInstructionIterator it(block_it.Current()); 64 ForwardInstructionIterator it(block_it.Current());
84 for (; !it.Done(); it.Advance()) { 65 for (; !it.Done(); it.Advance()) {
85 Instruction* instr = it.Current(); 66 Instruction* instr = it.Current();
86 if (instr->IsInstanceCall()) { 67 if (instr->IsInstanceCall()) {
87 InstanceCallInstr* call = instr->AsInstanceCall(); 68 InstanceCallInstr* call = instr->AsInstanceCall();
88 if (!call->HasICData()) { 69 if (!call->HasICData()) {
(...skipping 13 matching lines...) Expand all
102 } 83 }
103 } 84 }
104 85
105 86
106 // Optimize instance calls using cid. This is called after optimizer 87 // Optimize instance calls using cid. This is called after optimizer
107 // converted instance calls to instructions. Any remaining 88 // converted instance calls to instructions. Any remaining
108 // instance calls are either megamorphic calls, cannot be optimized or 89 // instance calls are either megamorphic calls, cannot be optimized or
109 // have no runtime type feedback collected. 90 // have no runtime type feedback collected.
110 // Attempts to convert an instance call (IC call) using propagated class-ids, 91 // Attempts to convert an instance call (IC call) using propagated class-ids,
111 // e.g., receiver class id, guarded-cid, or by guessing cid-s. 92 // e.g., receiver class id, guarded-cid, or by guessing cid-s.
112 void FlowGraphOptimizer::ApplyClassIds() { 93 void AotOptimizer::ApplyClassIds() {
113 ASSERT(current_iterator_ == NULL); 94 ASSERT(current_iterator_ == NULL);
114 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); 95 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator();
115 !block_it.Done(); 96 !block_it.Done();
116 block_it.Advance()) { 97 block_it.Advance()) {
117 ForwardInstructionIterator it(block_it.Current()); 98 ForwardInstructionIterator it(block_it.Current());
118 current_iterator_ = ⁢ 99 current_iterator_ = ⁢
119 for (; !it.Done(); it.Advance()) { 100 for (; !it.Done(); it.Advance()) {
120 Instruction* instr = it.Current(); 101 Instruction* instr = it.Current();
121 if (instr->IsInstanceCall()) { 102 if (instr->IsInstanceCall()) {
122 InstanceCallInstr* call = instr->AsInstanceCall(); 103 InstanceCallInstr* call = instr->AsInstanceCall();
(...skipping 10 matching lines...) Expand all
133 } 114 }
134 } 115 }
135 116
136 117
137 // TODO(srdjan): Test/support other number types as well. 118 // TODO(srdjan): Test/support other number types as well.
138 static bool IsNumberCid(intptr_t cid) { 119 static bool IsNumberCid(intptr_t cid) {
139 return (cid == kSmiCid) || (cid == kDoubleCid); 120 return (cid == kSmiCid) || (cid == kDoubleCid);
140 } 121 }
141 122
142 123
143 bool FlowGraphOptimizer::TryCreateICData(InstanceCallInstr* call) { 124 static void GetUniqueDynamicTarget(Isolate* isolate,
125 const String& fname,
126 Object* function) {
127 UniqueFunctionsSet functions_set(
128 isolate->object_store()->unique_dynamic_targets());
129 ASSERT(fname.IsSymbol());
130 *function = functions_set.GetOrNull(fname);
131 ASSERT(functions_set.Release().raw() ==
132 isolate->object_store()->unique_dynamic_targets());
133 }
134
135
136 bool AotOptimizer::TryCreateICData(InstanceCallInstr* call) {
144 ASSERT(call->HasICData()); 137 ASSERT(call->HasICData());
145 if (call->ic_data()->NumberOfUsedChecks() > 0) { 138 if (call->ic_data()->NumberOfUsedChecks() > 0) {
146 // This occurs when an instance call has too many checks, will be converted 139 // This occurs when an instance call has too many checks, will be converted
147 // to megamorphic call. 140 // to megamorphic call.
148 return false; 141 return false;
149 } 142 }
150 GrowableArray<intptr_t> class_ids(call->ic_data()->NumArgsTested()); 143 GrowableArray<intptr_t> class_ids(call->ic_data()->NumArgsTested());
151 ASSERT(call->ic_data()->NumArgsTested() <= call->ArgumentCount()); 144 ASSERT(call->ic_data()->NumArgsTested() <= call->ArgumentCount());
152 for (intptr_t i = 0; i < call->ic_data()->NumArgsTested(); i++) { 145 for (intptr_t i = 0; i < call->ic_data()->NumArgsTested(); i++) {
153 class_ids.Add(call->PushArgumentAt(i)->value()->Type()->ToCid()); 146 class_ids.Add(call->PushArgumentAt(i)->value()->Type()->ToCid());
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
210 if (class_ids.length() > 1) { 203 if (class_ids.length() > 1) {
211 ic_data.AddCheck(class_ids, function); 204 ic_data.AddCheck(class_ids, function);
212 } else { 205 } else {
213 ASSERT(class_ids.length() == 1); 206 ASSERT(class_ids.length() == 1);
214 ic_data.AddReceiverCheck(class_ids[0], function); 207 ic_data.AddReceiverCheck(class_ids[0], function);
215 } 208 }
216 call->set_ic_data(&ic_data); 209 call->set_ic_data(&ic_data);
217 return true; 210 return true;
218 } 211 }
219 212
220 #ifdef DART_PRECOMPILER 213 if (isolate()->object_store()->unique_dynamic_targets() != Array::null()) {
221 if (FLAG_precompilation &&
222 (isolate()->object_store()->unique_dynamic_targets() != Array::null())) {
223 // Check if the target is unique. 214 // Check if the target is unique.
224 Function& target_function = Function::Handle(Z); 215 Function& target_function = Function::Handle(Z);
225 Precompiler::GetUniqueDynamicTarget( 216 GetUniqueDynamicTarget(isolate(), call->function_name(), &target_function);
226 isolate(), call->function_name(), &target_function);
227 // Calls with named arguments must be resolved/checked at runtime. 217 // Calls with named arguments must be resolved/checked at runtime.
228 String& error_message = String::Handle(Z); 218 String& error_message = String::Handle(Z);
229 if (!target_function.IsNull() && 219 if (!target_function.IsNull() &&
230 !target_function.HasOptionalNamedParameters() && 220 !target_function.HasOptionalNamedParameters() &&
231 target_function.AreValidArgumentCounts(call->ArgumentCount(), 0, 221 target_function.AreValidArgumentCounts(call->ArgumentCount(), 0,
232 &error_message)) { 222 &error_message)) {
233 const intptr_t cid = Class::Handle(Z, target_function.Owner()).id(); 223 const intptr_t cid = Class::Handle(Z, target_function.Owner()).id();
234 const ICData& ic_data = ICData::ZoneHandle(Z, 224 const ICData& ic_data = ICData::ZoneHandle(Z,
235 ICData::NewFrom(*call->ic_data(), 1)); 225 ICData::NewFrom(*call->ic_data(), 1));
236 ic_data.AddReceiverCheck(cid, target_function); 226 ic_data.AddReceiverCheck(cid, target_function);
237 call->set_ic_data(&ic_data); 227 call->set_ic_data(&ic_data);
238 return true; 228 return true;
239 } 229 }
240 } 230 }
241 #endif
242 231
243 // Check if getter or setter in function's class and class is currently leaf. 232 // Check if getter or setter in function's class and class is currently leaf.
244 if (FLAG_guess_icdata_cid && 233 if (FLAG_guess_icdata_cid &&
245 ((call->token_kind() == Token::kGET) || 234 ((call->token_kind() == Token::kGET) ||
246 (call->token_kind() == Token::kSET))) { 235 (call->token_kind() == Token::kSET))) {
247 const Class& owner_class = Class::Handle(Z, function().Owner()); 236 const Class& owner_class = Class::Handle(Z, function().Owner());
248 if (!owner_class.is_abstract() && 237 if (!owner_class.is_abstract() &&
249 !CHA::HasSubclasses(owner_class) && 238 !CHA::HasSubclasses(owner_class) &&
250 !CHA::IsImplemented(owner_class)) { 239 !CHA::IsImplemented(owner_class)) {
251 const Array& args_desc_array = Array::Handle(Z, 240 const Array& args_desc_array = Array::Handle(Z,
(...skipping 11 matching lines...) Expand all
263 call->set_ic_data(&ic_data); 252 call->set_ic_data(&ic_data);
264 return true; 253 return true;
265 } 254 }
266 } 255 }
267 } 256 }
268 257
269 return false; 258 return false;
270 } 259 }
271 260
272 261
273 const ICData& FlowGraphOptimizer::TrySpecializeICData(const ICData& ic_data, 262 const ICData& AotOptimizer::TrySpecializeICData(const ICData& ic_data,
274 intptr_t cid) { 263 intptr_t cid) {
275 ASSERT(ic_data.NumArgsTested() == 1); 264 ASSERT(ic_data.NumArgsTested() == 1);
276 265
277 if ((ic_data.NumberOfUsedChecks() == 1) && ic_data.HasReceiverClassId(cid)) { 266 if ((ic_data.NumberOfUsedChecks() == 1) && ic_data.HasReceiverClassId(cid)) {
278 return ic_data; // Nothing to do 267 return ic_data; // Nothing to do
279 } 268 }
280 269
281 const Function& function = 270 const Function& function =
282 Function::Handle(Z, ic_data.GetTargetForReceiverClassId(cid)); 271 Function::Handle(Z, ic_data.GetTargetForReceiverClassId(cid));
283 // TODO(fschneider): Try looking up the function on the class if it is 272 // TODO(fschneider): Try looking up the function on the class if it is
284 // not found in the ICData. 273 // not found in the ICData.
285 if (!function.IsNull()) { 274 if (!function.IsNull()) {
286 const ICData& new_ic_data = ICData::ZoneHandle(Z, ICData::New( 275 const ICData& new_ic_data = ICData::ZoneHandle(Z, ICData::New(
287 Function::Handle(Z, ic_data.Owner()), 276 Function::Handle(Z, ic_data.Owner()),
288 String::Handle(Z, ic_data.target_name()), 277 String::Handle(Z, ic_data.target_name()),
289 Object::empty_array(), // Dummy argument descriptor. 278 Object::empty_array(), // Dummy argument descriptor.
290 ic_data.deopt_id(), 279 ic_data.deopt_id(),
291 ic_data.NumArgsTested())); 280 ic_data.NumArgsTested()));
292 new_ic_data.SetDeoptReasons(ic_data.DeoptReasons()); 281 new_ic_data.SetDeoptReasons(ic_data.DeoptReasons());
293 new_ic_data.AddReceiverCheck(cid, function); 282 new_ic_data.AddReceiverCheck(cid, function);
294 return new_ic_data; 283 return new_ic_data;
295 } 284 }
296 285
297 return ic_data; 286 return ic_data;
298 } 287 }
299 288
300 289
301 void FlowGraphOptimizer::SpecializePolymorphicInstanceCall( 290 void AotOptimizer::SpecializePolymorphicInstanceCall(
302 PolymorphicInstanceCallInstr* call) { 291 PolymorphicInstanceCallInstr* call) {
303 if (!FLAG_polymorphic_with_deopt) { 292 if (!FLAG_polymorphic_with_deopt) {
304 // Specialization adds receiver checks which can lead to deoptimization. 293 // Specialization adds receiver checks which can lead to deoptimization.
305 return; 294 return;
306 } 295 }
307 if (!call->with_checks()) { 296 if (!call->with_checks()) {
308 return; // Already specialized. 297 return; // Already specialized.
309 } 298 }
310 299
311 const intptr_t receiver_cid = 300 const intptr_t receiver_cid =
(...skipping 28 matching lines...) Expand all
340 329
341 static bool IsPositiveOrZeroSmiConst(Definition* d) { 330 static bool IsPositiveOrZeroSmiConst(Definition* d) {
342 ConstantInstr* const_instr = d->AsConstant(); 331 ConstantInstr* const_instr = d->AsConstant();
343 if ((const_instr != NULL) && (const_instr->value().IsSmi())) { 332 if ((const_instr != NULL) && (const_instr->value().IsSmi())) {
344 return Smi::Cast(const_instr->value()).Value() >= 0; 333 return Smi::Cast(const_instr->value()).Value() >= 0;
345 } 334 }
346 return false; 335 return false;
347 } 336 }
348 337
349 338
350 void FlowGraphOptimizer::OptimizeLeftShiftBitAndSmiOp( 339 void AotOptimizer::OptimizeLeftShiftBitAndSmiOp(
351 Definition* bit_and_instr, 340 Definition* bit_and_instr,
352 Definition* left_instr, 341 Definition* left_instr,
353 Definition* right_instr) { 342 Definition* right_instr) {
354 ASSERT(bit_and_instr != NULL); 343 ASSERT(bit_and_instr != NULL);
355 ASSERT((left_instr != NULL) && (right_instr != NULL)); 344 ASSERT((left_instr != NULL) && (right_instr != NULL));
356 345
357 // Check for pattern, smi_shift_left must be single-use. 346 // Check for pattern, smi_shift_left must be single-use.
358 bool is_positive_or_zero = IsPositiveOrZeroSmiConst(left_instr); 347 bool is_positive_or_zero = IsPositiveOrZeroSmiConst(left_instr);
359 if (!is_positive_or_zero) { 348 if (!is_positive_or_zero) {
360 is_positive_or_zero = IsPositiveOrZeroSmiConst(right_instr); 349 is_positive_or_zero = IsPositiveOrZeroSmiConst(right_instr);
(...skipping 17 matching lines...) Expand all
378 BinarySmiOpInstr* smi_op = new(Z) BinarySmiOpInstr( 367 BinarySmiOpInstr* smi_op = new(Z) BinarySmiOpInstr(
379 Token::kBIT_AND, 368 Token::kBIT_AND,
380 new(Z) Value(left_instr), 369 new(Z) Value(left_instr),
381 new(Z) Value(right_instr), 370 new(Z) Value(right_instr),
382 Thread::kNoDeoptId); // BIT_AND cannot deoptimize. 371 Thread::kNoDeoptId); // BIT_AND cannot deoptimize.
383 bit_and_instr->ReplaceWith(smi_op, current_iterator()); 372 bit_and_instr->ReplaceWith(smi_op, current_iterator());
384 } 373 }
385 } 374 }
386 375
387 376
388 void FlowGraphOptimizer::AppendExtractNthOutputForMerged(Definition* instr, 377 void AotOptimizer::AppendExtractNthOutputForMerged(Definition* instr,
389 intptr_t index, 378 intptr_t index,
390 Representation rep, 379 Representation rep,
391 intptr_t cid) { 380 intptr_t cid) {
392 ExtractNthOutputInstr* extract = 381 ExtractNthOutputInstr* extract =
393 new(Z) ExtractNthOutputInstr(new(Z) Value(instr), index, rep, cid); 382 new(Z) ExtractNthOutputInstr(new(Z) Value(instr), index, rep, cid);
394 instr->ReplaceUsesWith(extract); 383 instr->ReplaceUsesWith(extract);
395 flow_graph()->InsertAfter(instr, extract, NULL, FlowGraph::kValue); 384 flow_graph()->InsertAfter(instr, extract, NULL, FlowGraph::kValue);
396 } 385 }
397 386
398 387
399 // Dart: 388 // Dart:
400 // var x = d % 10; 389 // var x = d % 10;
401 // var y = d ~/ 10; 390 // var y = d ~/ 10;
402 // var z = x + y; 391 // var z = x + y;
403 // 392 //
404 // IL: 393 // IL:
405 // v4 <- %(v2, v3) 394 // v4 <- %(v2, v3)
406 // v5 <- ~/(v2, v3) 395 // v5 <- ~/(v2, v3)
407 // v6 <- +(v4, v5) 396 // v6 <- +(v4, v5)
408 // 397 //
409 // IL optimized: 398 // IL optimized:
410 // v4 <- DIVMOD(v2, v3); 399 // v4 <- DIVMOD(v2, v3);
411 // v5 <- LoadIndexed(v4, 0); // ~/ result 400 // v5 <- LoadIndexed(v4, 0); // ~/ result
412 // v6 <- LoadIndexed(v4, 1); // % result 401 // v6 <- LoadIndexed(v4, 1); // % result
413 // v7 <- +(v5, v6) 402 // v7 <- +(v5, v6)
414 // Because of the environment it is important that merged instruction replaces 403 // Because of the environment it is important that merged instruction replaces
415 // first original instruction encountered. 404 // first original instruction encountered.
416 void FlowGraphOptimizer::TryMergeTruncDivMod( 405 void AotOptimizer::TryMergeTruncDivMod(
417 GrowableArray<BinarySmiOpInstr*>* merge_candidates) { 406 GrowableArray<BinarySmiOpInstr*>* merge_candidates) {
418 if (merge_candidates->length() < 2) { 407 if (merge_candidates->length() < 2) {
419 // Need at least a TRUNCDIV and a MOD. 408 // Need at least a TRUNCDIV and a MOD.
420 return; 409 return;
421 } 410 }
422 for (intptr_t i = 0; i < merge_candidates->length(); i++) { 411 for (intptr_t i = 0; i < merge_candidates->length(); i++) {
423 BinarySmiOpInstr* curr_instr = (*merge_candidates)[i]; 412 BinarySmiOpInstr* curr_instr = (*merge_candidates)[i];
424 if (curr_instr == NULL) { 413 if (curr_instr == NULL) {
425 // Instruction was merged already. 414 // Instruction was merged already.
426 continue; 415 continue;
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
467 // more candidates are possible. 456 // more candidates are possible.
468 // TODO(srdjan): Allow merging of trunc-div/mod into truncDivMod. 457 // TODO(srdjan): Allow merging of trunc-div/mod into truncDivMod.
469 break; 458 break;
470 } 459 }
471 } 460 }
472 } 461 }
473 } 462 }
474 463
475 464
476 // Tries to merge MathUnary operations, in this case sinus and cosinus. 465 // Tries to merge MathUnary operations, in this case sinus and cosinus.
477 void FlowGraphOptimizer::TryMergeMathUnary( 466 void AotOptimizer::TryMergeMathUnary(
478 GrowableArray<MathUnaryInstr*>* merge_candidates) { 467 GrowableArray<MathUnaryInstr*>* merge_candidates) {
479 if (!FlowGraphCompiler::SupportsSinCos() || !CanUnboxDouble() || 468 if (!FlowGraphCompiler::SupportsSinCos() || !CanUnboxDouble() ||
480 !FLAG_merge_sin_cos) { 469 !FLAG_merge_sin_cos) {
481 return; 470 return;
482 } 471 }
483 if (merge_candidates->length() < 2) { 472 if (merge_candidates->length() < 2) {
484 // Need at least a SIN and a COS. 473 // Need at least a SIN and a COS.
485 return; 474 return;
486 } 475 }
487 for (intptr_t i = 0; i < merge_candidates->length(); i++) { 476 for (intptr_t i = 0; i < merge_candidates->length(); i++) {
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
528 break; 517 break;
529 } 518 }
530 } 519 }
531 } 520 }
532 } 521 }
533 522
534 523
535 // Optimize (a << b) & c pattern: if c is a positive Smi or zero, then the 524 // Optimize (a << b) & c pattern: if c is a positive Smi or zero, then the
536 // shift can be a truncating Smi shift-left and result is always Smi. 525 // shift can be a truncating Smi shift-left and result is always Smi.
537 // Merging occurs only per basic-block. 526 // Merging occurs only per basic-block.
538 void FlowGraphOptimizer::TryOptimizePatterns() { 527 void AotOptimizer::TryOptimizePatterns() {
539 if (!FLAG_truncating_left_shift) return; 528 if (!FLAG_truncating_left_shift) return;
540 ASSERT(current_iterator_ == NULL); 529 ASSERT(current_iterator_ == NULL);
541 GrowableArray<BinarySmiOpInstr*> div_mod_merge; 530 GrowableArray<BinarySmiOpInstr*> div_mod_merge;
542 GrowableArray<MathUnaryInstr*> sin_cos_merge; 531 GrowableArray<MathUnaryInstr*> sin_cos_merge;
543 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); 532 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator();
544 !block_it.Done(); 533 !block_it.Done();
545 block_it.Advance()) { 534 block_it.Advance()) {
546 // Merging only per basic-block. 535 // Merging only per basic-block.
547 div_mod_merge.Clear(); 536 div_mod_merge.Clear();
548 sin_cos_merge.Clear(); 537 sin_cos_merge.Clear();
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after
714 // Unboxed double operation can't handle case of two smis. 703 // Unboxed double operation can't handle case of two smis.
715 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) { 704 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) {
716 return false; 705 return false;
717 } 706 }
718 707
719 // Check that it have seen only smis and doubles. 708 // Check that it have seen only smis and doubles.
720 return HasTwoDoubleOrSmi(ic_data); 709 return HasTwoDoubleOrSmi(ic_data);
721 } 710 }
722 711
723 712
724 void FlowGraphOptimizer::ReplaceCall(Definition* call, 713 void AotOptimizer::ReplaceCall(Definition* call,
725 Definition* replacement) { 714 Definition* replacement) {
726 // Remove the original push arguments. 715 // Remove the original push arguments.
727 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { 716 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
728 PushArgumentInstr* push = call->PushArgumentAt(i); 717 PushArgumentInstr* push = call->PushArgumentAt(i);
729 push->ReplaceUsesWith(push->value()->definition()); 718 push->ReplaceUsesWith(push->value()->definition());
730 push->RemoveFromGraph(); 719 push->RemoveFromGraph();
731 } 720 }
732 call->ReplaceWith(replacement, current_iterator()); 721 call->ReplaceWith(replacement, current_iterator());
733 } 722 }
734 723
735 724
736 void FlowGraphOptimizer::AddCheckSmi(Definition* to_check, 725 void AotOptimizer::AddCheckSmi(Definition* to_check,
737 intptr_t deopt_id, 726 intptr_t deopt_id,
738 Environment* deopt_environment, 727 Environment* deopt_environment,
739 Instruction* insert_before) { 728 Instruction* insert_before) {
740 if (to_check->Type()->ToCid() != kSmiCid) { 729 if (to_check->Type()->ToCid() != kSmiCid) {
741 InsertBefore(insert_before, 730 InsertBefore(insert_before,
742 new(Z) CheckSmiInstr(new(Z) Value(to_check), 731 new(Z) CheckSmiInstr(new(Z) Value(to_check),
743 deopt_id, 732 deopt_id,
744 insert_before->token_pos()), 733 insert_before->token_pos()),
745 deopt_environment, 734 deopt_environment,
746 FlowGraph::kEffect); 735 FlowGraph::kEffect);
747 } 736 }
748 } 737 }
749 738
750 739
751 Instruction* FlowGraphOptimizer::GetCheckClass(Definition* to_check, 740 Instruction* AotOptimizer::GetCheckClass(Definition* to_check,
752 const ICData& unary_checks, 741 const ICData& unary_checks,
753 intptr_t deopt_id, 742 intptr_t deopt_id,
754 TokenPosition token_pos) { 743 TokenPosition token_pos) {
755 if ((unary_checks.NumberOfUsedChecks() == 1) && 744 if ((unary_checks.NumberOfUsedChecks() == 1) &&
756 unary_checks.HasReceiverClassId(kSmiCid)) { 745 unary_checks.HasReceiverClassId(kSmiCid)) {
757 return new(Z) CheckSmiInstr(new(Z) Value(to_check), 746 return new(Z) CheckSmiInstr(new(Z) Value(to_check),
758 deopt_id, 747 deopt_id,
759 token_pos); 748 token_pos);
760 } 749 }
761 return new(Z) CheckClassInstr( 750 return new(Z) CheckClassInstr(
762 new(Z) Value(to_check), deopt_id, unary_checks, token_pos); 751 new(Z) Value(to_check), deopt_id, unary_checks, token_pos);
763 } 752 }
764 753
765 754
766 void FlowGraphOptimizer::AddCheckClass(Definition* to_check, 755 void AotOptimizer::AddCheckClass(Definition* to_check,
767 const ICData& unary_checks, 756 const ICData& unary_checks,
768 intptr_t deopt_id, 757 intptr_t deopt_id,
769 Environment* deopt_environment, 758 Environment* deopt_environment,
770 Instruction* insert_before) { 759 Instruction* insert_before) {
771 // Type propagation has not run yet, we cannot eliminate the check. 760 // Type propagation has not run yet, we cannot eliminate the check.
772 Instruction* check = GetCheckClass( 761 Instruction* check = GetCheckClass(
773 to_check, unary_checks, deopt_id, insert_before->token_pos()); 762 to_check, unary_checks, deopt_id, insert_before->token_pos());
774 InsertBefore(insert_before, check, deopt_environment, FlowGraph::kEffect); 763 InsertBefore(insert_before, check, deopt_environment, FlowGraph::kEffect);
775 } 764 }
776 765
777 766
778 void FlowGraphOptimizer::AddReceiverCheck(InstanceCallInstr* call) { 767 void AotOptimizer::AddReceiverCheck(InstanceCallInstr* call) {
779 AddCheckClass(call->ArgumentAt(0), 768 AddCheckClass(call->ArgumentAt(0),
780 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks()), 769 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks()),
781 call->deopt_id(), 770 call->deopt_id(),
782 call->env(), 771 call->env(),
783 call); 772 call);
784 } 773 }
785 774
786 775
787 static bool ArgIsAlways(intptr_t cid, 776 static bool ArgIsAlways(intptr_t cid,
788 const ICData& ic_data, 777 const ICData& ic_data,
789 intptr_t arg_number) { 778 intptr_t arg_number) {
790 ASSERT(ic_data.NumArgsTested() > arg_number); 779 ASSERT(ic_data.NumArgsTested() > arg_number);
791 if (ic_data.NumberOfUsedChecks() == 0) { 780 if (ic_data.NumberOfUsedChecks() == 0) {
792 return false; 781 return false;
793 } 782 }
794 const intptr_t num_checks = ic_data.NumberOfChecks(); 783 const intptr_t num_checks = ic_data.NumberOfChecks();
795 for (intptr_t i = 0; i < num_checks; i++) { 784 for (intptr_t i = 0; i < num_checks; i++) {
796 if (ic_data.IsUsedAt(i) && ic_data.GetClassIdAt(i, arg_number) != cid) { 785 if (ic_data.IsUsedAt(i) && ic_data.GetClassIdAt(i, arg_number) != cid) {
797 return false; 786 return false;
798 } 787 }
799 } 788 }
800 return true; 789 return true;
801 } 790 }
802 791
803 792
804 bool FlowGraphOptimizer::TryReplaceWithIndexedOp(InstanceCallInstr* call) { 793 bool AotOptimizer::TryReplaceWithIndexedOp(InstanceCallInstr* call) {
805 // Check for monomorphic IC data. 794 // Check for monomorphic IC data.
806 if (!call->HasICData()) return false; 795 if (!call->HasICData()) return false;
807 const ICData& ic_data = 796 const ICData& ic_data =
808 ICData::Handle(Z, call->ic_data()->AsUnaryClassChecks()); 797 ICData::Handle(Z, call->ic_data()->AsUnaryClassChecks());
809 if (ic_data.NumberOfChecks() != 1) { 798 if (ic_data.NumberOfChecks() != 1) {
810 return false; 799 return false;
811 } 800 }
812 return TryReplaceInstanceCallWithInline(call); 801 return TryReplaceInstanceCallWithInline(call);
813 } 802 }
814 803
(...skipping 11 matching lines...) Expand all
826 } else { 815 } else {
827 return d->IsStringFromCharCode(); 816 return d->IsStringFromCharCode();
828 } 817 }
829 } 818 }
830 819
831 820
832 // Returns true if the string comparison was converted into char-code 821 // Returns true if the string comparison was converted into char-code
833 // comparison. Conversion is only possible for strings of length one. 822 // comparison. Conversion is only possible for strings of length one.
834 // E.g., detect str[x] == "x"; and use an integer comparison of char-codes. 823 // E.g., detect str[x] == "x"; and use an integer comparison of char-codes.
835 // TODO(srdjan): Expand for two-byte and external strings. 824 // TODO(srdjan): Expand for two-byte and external strings.
836 bool FlowGraphOptimizer::TryStringLengthOneEquality(InstanceCallInstr* call, 825 bool AotOptimizer::TryStringLengthOneEquality(InstanceCallInstr* call,
837 Token::Kind op_kind) { 826 Token::Kind op_kind) {
838 ASSERT(HasOnlyTwoOf(*call->ic_data(), kOneByteStringCid)); 827 ASSERT(HasOnlyTwoOf(*call->ic_data(), kOneByteStringCid));
839 // Check that left and right are length one strings (either string constants 828 // Check that left and right are length one strings (either string constants
840 // or results of string-from-char-code. 829 // or results of string-from-char-code.
841 Definition* left = call->ArgumentAt(0); 830 Definition* left = call->ArgumentAt(0);
842 Definition* right = call->ArgumentAt(1); 831 Definition* right = call->ArgumentAt(1);
843 Value* left_val = NULL; 832 Value* left_val = NULL;
844 Definition* to_remove_left = NULL; 833 Definition* to_remove_left = NULL;
845 if (IsLengthOneString(right)) { 834 if (IsLengthOneString(right)) {
846 // Swap, since we know that both arguments are strings 835 // Swap, since we know that both arguments are strings
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
913 to_remove_right->RemoveFromGraph(); 902 to_remove_right->RemoveFromGraph();
914 } 903 }
915 return true; 904 return true;
916 } 905 }
917 return false; 906 return false;
918 } 907 }
919 908
920 909
921 static bool SmiFitsInDouble() { return kSmiBits < 53; } 910 static bool SmiFitsInDouble() { return kSmiBits < 53; }
922 911
923 bool FlowGraphOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call, 912 bool AotOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call,
924 Token::Kind op_kind) { 913 Token::Kind op_kind) {
925 const ICData& ic_data = *call->ic_data(); 914 const ICData& ic_data = *call->ic_data();
926 ASSERT(ic_data.NumArgsTested() == 2); 915 ASSERT(ic_data.NumArgsTested() == 2);
927 916
928 ASSERT(call->ArgumentCount() == 2); 917 ASSERT(call->ArgumentCount() == 2);
929 Definition* left = call->ArgumentAt(0); 918 Definition* left = call->ArgumentAt(0);
930 Definition* right = call->ArgumentAt(1); 919 Definition* right = call->ArgumentAt(1);
931 920
932 intptr_t cid = kIllegalCid; 921 intptr_t cid = kIllegalCid;
933 if (HasOnlyTwoOf(ic_data, kOneByteStringCid)) { 922 if (HasOnlyTwoOf(ic_data, kOneByteStringCid)) {
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
1022 op_kind, 1011 op_kind,
1023 new(Z) Value(left), 1012 new(Z) Value(left),
1024 new(Z) Value(right), 1013 new(Z) Value(right),
1025 cid, 1014 cid,
1026 call->deopt_id()); 1015 call->deopt_id());
1027 ReplaceCall(call, comp); 1016 ReplaceCall(call, comp);
1028 return true; 1017 return true;
1029 } 1018 }
1030 1019
1031 1020
1032 bool FlowGraphOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call, 1021 bool AotOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call,
1033 Token::Kind op_kind) { 1022 Token::Kind op_kind) {
1034 const ICData& ic_data = *call->ic_data(); 1023 const ICData& ic_data = *call->ic_data();
1035 ASSERT(ic_data.NumArgsTested() == 2); 1024 ASSERT(ic_data.NumArgsTested() == 2);
1036 1025
1037 ASSERT(call->ArgumentCount() == 2); 1026 ASSERT(call->ArgumentCount() == 2);
1038 Definition* left = call->ArgumentAt(0); 1027 Definition* left = call->ArgumentAt(0);
1039 Definition* right = call->ArgumentAt(1); 1028 Definition* right = call->ArgumentAt(1);
1040 1029
1041 intptr_t cid = kIllegalCid; 1030 intptr_t cid = kIllegalCid;
1042 if (HasOnlyTwoOf(ic_data, kSmiCid)) { 1031 if (HasOnlyTwoOf(ic_data, kSmiCid)) {
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
1084 op_kind, 1073 op_kind,
1085 new(Z) Value(left), 1074 new(Z) Value(left),
1086 new(Z) Value(right), 1075 new(Z) Value(right),
1087 cid, 1076 cid,
1088 call->deopt_id()); 1077 call->deopt_id());
1089 ReplaceCall(call, comp); 1078 ReplaceCall(call, comp);
1090 return true; 1079 return true;
1091 } 1080 }
1092 1081
1093 1082
1094 bool FlowGraphOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call, 1083 bool AotOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call,
1095 Token::Kind op_kind) { 1084 Token::Kind op_kind) {
1096 intptr_t operands_type = kIllegalCid; 1085 intptr_t operands_type = kIllegalCid;
1097 ASSERT(call->HasICData()); 1086 ASSERT(call->HasICData());
1098 const ICData& ic_data = *call->ic_data(); 1087 const ICData& ic_data = *call->ic_data();
1099 switch (op_kind) { 1088 switch (op_kind) {
1100 case Token::kADD: 1089 case Token::kADD:
1101 case Token::kSUB: 1090 case Token::kSUB:
1102 case Token::kMUL: 1091 case Token::kMUL:
1103 if (HasOnlyTwoOf(ic_data, kSmiCid)) { 1092 if (HasOnlyTwoOf(ic_data, kSmiCid)) {
1104 // Don't generate smi code if the IC data is marked because 1093 // Don't generate smi code if the IC data is marked because
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after
1293 op_kind, 1282 op_kind,
1294 new(Z) Value(left), 1283 new(Z) Value(left),
1295 new(Z) Value(right), 1284 new(Z) Value(right),
1296 call->deopt_id()); 1285 call->deopt_id());
1297 ReplaceCall(call, bin_op); 1286 ReplaceCall(call, bin_op);
1298 } 1287 }
1299 return true; 1288 return true;
1300 } 1289 }
1301 1290
1302 1291
1303 bool FlowGraphOptimizer::TryReplaceWithUnaryOp(InstanceCallInstr* call, 1292 bool AotOptimizer::TryReplaceWithUnaryOp(InstanceCallInstr* call,
1304 Token::Kind op_kind) { 1293 Token::Kind op_kind) {
1305 ASSERT(call->ArgumentCount() == 1); 1294 ASSERT(call->ArgumentCount() == 1);
1306 Definition* input = call->ArgumentAt(0); 1295 Definition* input = call->ArgumentAt(0);
1307 Definition* unary_op = NULL; 1296 Definition* unary_op = NULL;
1308 if (HasOnlyOneSmi(*call->ic_data())) { 1297 if (HasOnlyOneSmi(*call->ic_data())) {
1309 InsertBefore(call, 1298 InsertBefore(call,
1310 new(Z) CheckSmiInstr(new(Z) Value(input), 1299 new(Z) CheckSmiInstr(new(Z) Value(input),
1311 call->deopt_id(), 1300 call->deopt_id(),
1312 call->token_pos()), 1301 call->token_pos()),
1313 call->env(), 1302 call->env(),
(...skipping 14 matching lines...) Expand all
1328 } else { 1317 } else {
1329 return false; 1318 return false;
1330 } 1319 }
1331 ASSERT(unary_op != NULL); 1320 ASSERT(unary_op != NULL);
1332 ReplaceCall(call, unary_op); 1321 ReplaceCall(call, unary_op);
1333 return true; 1322 return true;
1334 } 1323 }
1335 1324
1336 1325
1337 // Using field class 1326 // Using field class
1338 RawField* FlowGraphOptimizer::GetField(intptr_t class_id, 1327 RawField* AotOptimizer::GetField(intptr_t class_id,
1339 const String& field_name) { 1328 const String& field_name) {
1340 Class& cls = Class::Handle(Z, isolate()->class_table()->At(class_id)); 1329 Class& cls = Class::Handle(Z, isolate()->class_table()->At(class_id));
1341 Field& field = Field::Handle(Z); 1330 Field& field = Field::Handle(Z);
1342 while (!cls.IsNull()) { 1331 while (!cls.IsNull()) {
1343 field = cls.LookupInstanceField(field_name); 1332 field = cls.LookupInstanceField(field_name);
1344 if (!field.IsNull()) { 1333 if (!field.IsNull()) {
1345 return field.raw(); 1334 return field.raw();
1346 } 1335 }
1347 cls = cls.SuperClass(); 1336 cls = cls.SuperClass();
1348 } 1337 }
1349 return Field::null(); 1338 return Field::null();
1350 } 1339 }
1351 1340
1352 1341
1353 // Use CHA to determine if the call needs a class check: if the callee's 1342 // Use CHA to determine if the call needs a class check: if the callee's
1354 // receiver is the same as the caller's receiver and there are no overriden 1343 // receiver is the same as the caller's receiver and there are no overriden
1355 // callee functions, then no class check is needed. 1344 // callee functions, then no class check is needed.
1356 bool FlowGraphOptimizer::InstanceCallNeedsClassCheck( 1345 bool AotOptimizer::InstanceCallNeedsClassCheck(
1357 InstanceCallInstr* call, RawFunction::Kind kind) const { 1346 InstanceCallInstr* call, RawFunction::Kind kind) const {
1358 if (!FLAG_use_cha_deopt && !isolate()->all_classes_finalized()) { 1347 if (!FLAG_use_cha_deopt && !isolate()->all_classes_finalized()) {
1359 // Even if class or function are private, lazy class finalization 1348 // Even if class or function are private, lazy class finalization
1360 // may later add overriding methods. 1349 // may later add overriding methods.
1361 return true; 1350 return true;
1362 } 1351 }
1363 Definition* callee_receiver = call->ArgumentAt(0); 1352 Definition* callee_receiver = call->ArgumentAt(0);
1364 ASSERT(callee_receiver != NULL); 1353 ASSERT(callee_receiver != NULL);
1365 const Function& function = flow_graph_->function(); 1354 const Function& function = flow_graph_->function();
1366 if (function.IsDynamicFunction() && 1355 if (function.IsDynamicFunction() &&
(...skipping 10 matching lines...) Expand all
1377 name.ToCString(), cls.ToCString()); 1366 name.ToCString(), cls.ToCString());
1378 } 1367 }
1379 thread()->cha()->AddToLeafClasses(cls); 1368 thread()->cha()->AddToLeafClasses(cls);
1380 return false; 1369 return false;
1381 } 1370 }
1382 } 1371 }
1383 return true; 1372 return true;
1384 } 1373 }
1385 1374
1386 1375
1387 bool FlowGraphOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call, 1376 bool AotOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call,
1388 bool allow_check) { 1377 bool allow_check) {
1389 ASSERT(call->HasICData()); 1378 ASSERT(call->HasICData());
1390 const ICData& ic_data = *call->ic_data(); 1379 const ICData& ic_data = *call->ic_data();
1391 ASSERT(ic_data.HasOneTarget()); 1380 ASSERT(ic_data.HasOneTarget());
1392 GrowableArray<intptr_t> class_ids; 1381 GrowableArray<intptr_t> class_ids;
1393 ic_data.GetClassIdsAt(0, &class_ids); 1382 ic_data.GetClassIdsAt(0, &class_ids);
1394 ASSERT(class_ids.length() == 1); 1383 ASSERT(class_ids.length() == 1);
1395 // Inline implicit instance getter. 1384 // Inline implicit instance getter.
1396 const String& field_name = 1385 const String& field_name =
1397 String::Handle(Z, Field::NameFromGetter(call->function_name())); 1386 String::Handle(Z, Field::NameFromGetter(call->function_name()));
(...skipping 30 matching lines...) Expand all
1428 for (Value::Iterator it(load->input_use_list()); 1417 for (Value::Iterator it(load->input_use_list());
1429 !it.Done(); 1418 !it.Done();
1430 it.Advance()) { 1419 it.Advance()) {
1431 it.Current()->SetReachingType(NULL); 1420 it.Current()->SetReachingType(NULL);
1432 } 1421 }
1433 } 1422 }
1434 return true; 1423 return true;
1435 } 1424 }
1436 1425
1437 1426
1438 bool FlowGraphOptimizer::InlineFloat32x4Getter(InstanceCallInstr* call, 1427 bool AotOptimizer::InlineFloat32x4Getter(InstanceCallInstr* call,
1439 MethodRecognizer::Kind getter) { 1428 MethodRecognizer::Kind getter) {
1440 if (!ShouldInlineSimd()) { 1429 if (!ShouldInlineSimd()) {
1441 return false; 1430 return false;
1442 } 1431 }
1443 AddCheckClass(call->ArgumentAt(0), 1432 AddCheckClass(call->ArgumentAt(0),
1444 ICData::ZoneHandle( 1433 ICData::ZoneHandle(
1445 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), 1434 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
1446 call->deopt_id(), 1435 call->deopt_id(),
1447 call->env(), 1436 call->env(),
1448 call); 1437 call);
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
1503 mask, 1492 mask,
1504 call->deopt_id()); 1493 call->deopt_id());
1505 ReplaceCall(call, instr); 1494 ReplaceCall(call, instr);
1506 return true; 1495 return true;
1507 } 1496 }
1508 UNREACHABLE(); 1497 UNREACHABLE();
1509 return false; 1498 return false;
1510 } 1499 }
1511 1500
1512 1501
1513 bool FlowGraphOptimizer::InlineFloat64x2Getter(InstanceCallInstr* call, 1502 bool AotOptimizer::InlineFloat64x2Getter(InstanceCallInstr* call,
1514 MethodRecognizer::Kind getter) { 1503 MethodRecognizer::Kind getter) {
1515 if (!ShouldInlineSimd()) { 1504 if (!ShouldInlineSimd()) {
1516 return false; 1505 return false;
1517 } 1506 }
1518 AddCheckClass(call->ArgumentAt(0), 1507 AddCheckClass(call->ArgumentAt(0),
1519 ICData::ZoneHandle( 1508 ICData::ZoneHandle(
1520 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), 1509 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
1521 call->deopt_id(), 1510 call->deopt_id(),
1522 call->env(), 1511 call->env(),
1523 call); 1512 call);
1524 if ((getter == MethodRecognizer::kFloat64x2GetX) || 1513 if ((getter == MethodRecognizer::kFloat64x2GetX) ||
1525 (getter == MethodRecognizer::kFloat64x2GetY)) { 1514 (getter == MethodRecognizer::kFloat64x2GetY)) {
1526 Simd64x2ShuffleInstr* instr = new(Z) Simd64x2ShuffleInstr( 1515 Simd64x2ShuffleInstr* instr = new(Z) Simd64x2ShuffleInstr(
1527 getter, 1516 getter,
1528 new(Z) Value(call->ArgumentAt(0)), 1517 new(Z) Value(call->ArgumentAt(0)),
1529 0, 1518 0,
1530 call->deopt_id()); 1519 call->deopt_id());
1531 ReplaceCall(call, instr); 1520 ReplaceCall(call, instr);
1532 return true; 1521 return true;
1533 } 1522 }
1534 UNREACHABLE(); 1523 UNREACHABLE();
1535 return false; 1524 return false;
1536 } 1525 }
1537 1526
1538 1527
1539 bool FlowGraphOptimizer::InlineInt32x4Getter(InstanceCallInstr* call, 1528 bool AotOptimizer::InlineInt32x4Getter(InstanceCallInstr* call,
1540 MethodRecognizer::Kind getter) { 1529 MethodRecognizer::Kind getter) {
1541 if (!ShouldInlineSimd()) { 1530 if (!ShouldInlineSimd()) {
1542 return false; 1531 return false;
1543 } 1532 }
1544 AddCheckClass(call->ArgumentAt(0), 1533 AddCheckClass(call->ArgumentAt(0),
1545 ICData::ZoneHandle( 1534 ICData::ZoneHandle(
1546 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), 1535 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
1547 call->deopt_id(), 1536 call->deopt_id(),
1548 call->env(), 1537 call->env(),
1549 call); 1538 call);
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
1604 Int32x4GetFlagInstr* instr = new(Z) Int32x4GetFlagInstr( 1593 Int32x4GetFlagInstr* instr = new(Z) Int32x4GetFlagInstr(
1605 getter, 1594 getter,
1606 new(Z) Value(call->ArgumentAt(0)), 1595 new(Z) Value(call->ArgumentAt(0)),
1607 call->deopt_id()); 1596 call->deopt_id());
1608 ReplaceCall(call, instr); 1597 ReplaceCall(call, instr);
1609 return true; 1598 return true;
1610 } 1599 }
1611 } 1600 }
1612 1601
1613 1602
1614 bool FlowGraphOptimizer::InlineFloat32x4BinaryOp(InstanceCallInstr* call, 1603 bool AotOptimizer::InlineFloat32x4BinaryOp(InstanceCallInstr* call,
1615 Token::Kind op_kind) { 1604 Token::Kind op_kind) {
1616 if (!ShouldInlineSimd()) { 1605 if (!ShouldInlineSimd()) {
1617 return false; 1606 return false;
1618 } 1607 }
1619 ASSERT(call->ArgumentCount() == 2); 1608 ASSERT(call->ArgumentCount() == 2);
1620 Definition* left = call->ArgumentAt(0); 1609 Definition* left = call->ArgumentAt(0);
1621 Definition* right = call->ArgumentAt(1); 1610 Definition* right = call->ArgumentAt(1);
1622 // Type check left. 1611 // Type check left.
1623 AddCheckClass(left, 1612 AddCheckClass(left,
1624 ICData::ZoneHandle( 1613 ICData::ZoneHandle(
(...skipping 12 matching lines...) Expand all
1637 BinaryFloat32x4OpInstr* float32x4_bin_op = 1626 BinaryFloat32x4OpInstr* float32x4_bin_op =
1638 new(Z) BinaryFloat32x4OpInstr( 1627 new(Z) BinaryFloat32x4OpInstr(
1639 op_kind, new(Z) Value(left), new(Z) Value(right), 1628 op_kind, new(Z) Value(left), new(Z) Value(right),
1640 call->deopt_id()); 1629 call->deopt_id());
1641 ReplaceCall(call, float32x4_bin_op); 1630 ReplaceCall(call, float32x4_bin_op);
1642 1631
1643 return true; 1632 return true;
1644 } 1633 }
1645 1634
1646 1635
1647 bool FlowGraphOptimizer::InlineInt32x4BinaryOp(InstanceCallInstr* call, 1636 bool AotOptimizer::InlineInt32x4BinaryOp(InstanceCallInstr* call,
1648 Token::Kind op_kind) { 1637 Token::Kind op_kind) {
1649 if (!ShouldInlineSimd()) { 1638 if (!ShouldInlineSimd()) {
1650 return false; 1639 return false;
1651 } 1640 }
1652 ASSERT(call->ArgumentCount() == 2); 1641 ASSERT(call->ArgumentCount() == 2);
1653 Definition* left = call->ArgumentAt(0); 1642 Definition* left = call->ArgumentAt(0);
1654 Definition* right = call->ArgumentAt(1); 1643 Definition* right = call->ArgumentAt(1);
1655 // Type check left. 1644 // Type check left.
1656 AddCheckClass(left, 1645 AddCheckClass(left,
1657 ICData::ZoneHandle( 1646 ICData::ZoneHandle(
(...skipping 11 matching lines...) Expand all
1669 // Replace call. 1658 // Replace call.
1670 BinaryInt32x4OpInstr* int32x4_bin_op = 1659 BinaryInt32x4OpInstr* int32x4_bin_op =
1671 new(Z) BinaryInt32x4OpInstr( 1660 new(Z) BinaryInt32x4OpInstr(
1672 op_kind, new(Z) Value(left), new(Z) Value(right), 1661 op_kind, new(Z) Value(left), new(Z) Value(right),
1673 call->deopt_id()); 1662 call->deopt_id());
1674 ReplaceCall(call, int32x4_bin_op); 1663 ReplaceCall(call, int32x4_bin_op);
1675 return true; 1664 return true;
1676 } 1665 }
1677 1666
1678 1667
1679 bool FlowGraphOptimizer::InlineFloat64x2BinaryOp(InstanceCallInstr* call, 1668 bool AotOptimizer::InlineFloat64x2BinaryOp(InstanceCallInstr* call,
1680 Token::Kind op_kind) { 1669 Token::Kind op_kind) {
1681 if (!ShouldInlineSimd()) { 1670 if (!ShouldInlineSimd()) {
1682 return false; 1671 return false;
1683 } 1672 }
1684 ASSERT(call->ArgumentCount() == 2); 1673 ASSERT(call->ArgumentCount() == 2);
1685 Definition* left = call->ArgumentAt(0); 1674 Definition* left = call->ArgumentAt(0);
1686 Definition* right = call->ArgumentAt(1); 1675 Definition* right = call->ArgumentAt(1);
1687 // Type check left. 1676 // Type check left.
1688 AddCheckClass(left, 1677 AddCheckClass(left,
1689 ICData::ZoneHandle( 1678 ICData::ZoneHandle(
(...skipping 13 matching lines...) Expand all
1703 new(Z) BinaryFloat64x2OpInstr( 1692 new(Z) BinaryFloat64x2OpInstr(
1704 op_kind, new(Z) Value(left), new(Z) Value(right), 1693 op_kind, new(Z) Value(left), new(Z) Value(right),
1705 call->deopt_id()); 1694 call->deopt_id());
1706 ReplaceCall(call, float64x2_bin_op); 1695 ReplaceCall(call, float64x2_bin_op);
1707 return true; 1696 return true;
1708 } 1697 }
1709 1698
1710 1699
1711 // Only unique implicit instance getters can be currently handled. 1700 // Only unique implicit instance getters can be currently handled.
1712 // Returns false if 'allow_check' is false and a check is needed. 1701 // Returns false if 'allow_check' is false and a check is needed.
1713 bool FlowGraphOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call, 1702 bool AotOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call,
1714 bool allow_check) { 1703 bool allow_check) {
1715 ASSERT(call->HasICData()); 1704 ASSERT(call->HasICData());
1716 const ICData& ic_data = *call->ic_data(); 1705 const ICData& ic_data = *call->ic_data();
1717 if (ic_data.NumberOfUsedChecks() == 0) { 1706 if (ic_data.NumberOfUsedChecks() == 0) {
1718 // No type feedback collected. 1707 // No type feedback collected.
1719 return false; 1708 return false;
1720 } 1709 }
1721 1710
1722 if (!ic_data.HasOneTarget()) { 1711 if (!ic_data.HasOneTarget()) {
1723 // Polymorphic sites are inlined like normal methods by conventional 1712 // Polymorphic sites are inlined like normal methods by conventional
1724 // inlining in FlowGraphInliner. 1713 // inlining in FlowGraphInliner.
1725 return false; 1714 return false;
1726 } 1715 }
1727 1716
1728 const Function& target = Function::Handle(Z, ic_data.GetTargetAt(0)); 1717 const Function& target = Function::Handle(Z, ic_data.GetTargetAt(0));
1729 if (target.kind() != RawFunction::kImplicitGetter) { 1718 if (target.kind() != RawFunction::kImplicitGetter) {
1730 // Non-implicit getters are inlined like normal methods by conventional 1719 // Non-implicit getters are inlined like normal methods by conventional
1731 // inlining in FlowGraphInliner. 1720 // inlining in FlowGraphInliner.
1732 return false; 1721 return false;
1733 } 1722 }
1734 return InlineImplicitInstanceGetter(call, allow_check); 1723 return InlineImplicitInstanceGetter(call, allow_check);
1735 } 1724 }
1736 1725
1737 1726
1738 bool FlowGraphOptimizer::TryReplaceInstanceCallWithInline( 1727 bool AotOptimizer::TryReplaceInstanceCallWithInline(
1739 InstanceCallInstr* call) { 1728 InstanceCallInstr* call) {
1740 Function& target = Function::Handle(Z); 1729 Function& target = Function::Handle(Z);
1741 GrowableArray<intptr_t> class_ids; 1730 GrowableArray<intptr_t> class_ids;
1742 call->ic_data()->GetCheckAt(0, &class_ids, &target); 1731 call->ic_data()->GetCheckAt(0, &class_ids, &target);
1743 const intptr_t receiver_cid = class_ids[0]; 1732 const intptr_t receiver_cid = class_ids[0];
1744 1733
1745 TargetEntryInstr* entry; 1734 TargetEntryInstr* entry;
1746 Definition* last; 1735 Definition* last;
1747 if (!FlowGraphInliner::TryInlineRecognizedMethod(flow_graph_, 1736 if (!FlowGraphInliner::TryInlineRecognizedMethod(flow_graph_,
1748 receiver_cid, 1737 receiver_cid,
(...skipping 23 matching lines...) Expand all
1772 last->LinkTo(call); 1761 last->LinkTo(call);
1773 // Remove through the iterator. 1762 // Remove through the iterator.
1774 ASSERT(current_iterator()->Current() == call); 1763 ASSERT(current_iterator()->Current() == call);
1775 current_iterator()->RemoveCurrentFromGraph(); 1764 current_iterator()->RemoveCurrentFromGraph();
1776 call->set_previous(NULL); 1765 call->set_previous(NULL);
1777 call->set_next(NULL); 1766 call->set_next(NULL);
1778 return true; 1767 return true;
1779 } 1768 }
1780 1769
1781 1770
1782 void FlowGraphOptimizer::ReplaceWithMathCFunction( 1771 void AotOptimizer::ReplaceWithMathCFunction(
1783 InstanceCallInstr* call, 1772 InstanceCallInstr* call,
1784 MethodRecognizer::Kind recognized_kind) { 1773 MethodRecognizer::Kind recognized_kind) {
1785 AddReceiverCheck(call); 1774 AddReceiverCheck(call);
1786 ZoneGrowableArray<Value*>* args = 1775 ZoneGrowableArray<Value*>* args =
1787 new(Z) ZoneGrowableArray<Value*>(call->ArgumentCount()); 1776 new(Z) ZoneGrowableArray<Value*>(call->ArgumentCount());
1788 for (intptr_t i = 0; i < call->ArgumentCount(); i++) { 1777 for (intptr_t i = 0; i < call->ArgumentCount(); i++) {
1789 args->Add(new(Z) Value(call->ArgumentAt(i))); 1778 args->Add(new(Z) Value(call->ArgumentAt(i)));
1790 } 1779 }
1791 InvokeMathCFunctionInstr* invoke = 1780 InvokeMathCFunctionInstr* invoke =
1792 new(Z) InvokeMathCFunctionInstr(args, 1781 new(Z) InvokeMathCFunctionInstr(args,
(...skipping 20 matching lines...) Expand all
1813 case kTypedDataFloat32x4ArrayCid: 1802 case kTypedDataFloat32x4ArrayCid:
1814 case kTypedDataInt32x4ArrayCid: 1803 case kTypedDataInt32x4ArrayCid:
1815 return true; 1804 return true;
1816 default: 1805 default:
1817 return false; 1806 return false;
1818 } 1807 }
1819 } 1808 }
1820 1809
1821 1810
1822 // Inline only simple, frequently called core library methods. 1811 // Inline only simple, frequently called core library methods.
1823 bool FlowGraphOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) { 1812 bool AotOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) {
1824 ASSERT(call->HasICData()); 1813 ASSERT(call->HasICData());
1825 const ICData& ic_data = *call->ic_data(); 1814 const ICData& ic_data = *call->ic_data();
1826 if ((ic_data.NumberOfUsedChecks() == 0) || !ic_data.HasOneTarget()) { 1815 if ((ic_data.NumberOfUsedChecks() == 0) || !ic_data.HasOneTarget()) {
1827 // No type feedback collected or multiple targets found. 1816 // No type feedback collected or multiple targets found.
1828 return false; 1817 return false;
1829 } 1818 }
1830 1819
1831 Function& target = Function::Handle(Z); 1820 Function& target = Function::Handle(Z);
1832 GrowableArray<intptr_t> class_ids; 1821 GrowableArray<intptr_t> class_ids;
1833 ic_data.GetCheckAt(0, &class_ids, &target); 1822 ic_data.GetCheckAt(0, &class_ids, &target);
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after
2046 new(Z) Value(int32_mask), 2035 new(Z) Value(int32_mask),
2047 call->deopt_id()); 2036 call->deopt_id());
2048 ReplaceCall(call, bit_and); 2037 ReplaceCall(call, bit_and);
2049 return true; 2038 return true;
2050 } 2039 }
2051 } 2040 }
2052 return false; 2041 return false;
2053 } 2042 }
2054 2043
2055 2044
2056 bool FlowGraphOptimizer::TryInlineFloat32x4Constructor( 2045 bool AotOptimizer::TryInlineFloat32x4Constructor(
2057 StaticCallInstr* call, 2046 StaticCallInstr* call,
2058 MethodRecognizer::Kind recognized_kind) { 2047 MethodRecognizer::Kind recognized_kind) {
2059 if (FLAG_precompilation) { 2048 ASSERT(FLAG_precompilation);
rmacnak 2016/02/19 23:46:03 Keep comment: Cannot handle unboxed instructions.
Florian Schneider 2016/02/23 15:27:03 Done.
2060 // Cannot handle unboxed instructions.
2061 return false;
2062 }
2063 if (!ShouldInlineSimd()) {
2064 return false;
2065 }
2066 if (recognized_kind == MethodRecognizer::kFloat32x4Zero) {
2067 Float32x4ZeroInstr* zero = new(Z) Float32x4ZeroInstr();
2068 ReplaceCall(call, zero);
2069 return true;
2070 } else if (recognized_kind == MethodRecognizer::kFloat32x4Splat) {
2071 Float32x4SplatInstr* splat =
2072 new(Z) Float32x4SplatInstr(
2073 new(Z) Value(call->ArgumentAt(1)), call->deopt_id());
2074 ReplaceCall(call, splat);
2075 return true;
2076 } else if (recognized_kind == MethodRecognizer::kFloat32x4Constructor) {
2077 Float32x4ConstructorInstr* con =
2078 new(Z) Float32x4ConstructorInstr(
2079 new(Z) Value(call->ArgumentAt(1)),
2080 new(Z) Value(call->ArgumentAt(2)),
2081 new(Z) Value(call->ArgumentAt(3)),
2082 new(Z) Value(call->ArgumentAt(4)),
2083 call->deopt_id());
2084 ReplaceCall(call, con);
2085 return true;
2086 } else if (recognized_kind == MethodRecognizer::kFloat32x4FromInt32x4Bits) {
2087 Int32x4ToFloat32x4Instr* cast =
2088 new(Z) Int32x4ToFloat32x4Instr(
2089 new(Z) Value(call->ArgumentAt(1)), call->deopt_id());
2090 ReplaceCall(call, cast);
2091 return true;
2092 } else if (recognized_kind == MethodRecognizer::kFloat32x4FromFloat64x2) {
2093 Float64x2ToFloat32x4Instr* cast =
2094 new(Z) Float64x2ToFloat32x4Instr(
2095 new(Z) Value(call->ArgumentAt(1)), call->deopt_id());
2096 ReplaceCall(call, cast);
2097 return true;
2098 }
2099 return false; 2049 return false;
2100 } 2050 }
2101 2051
2102 2052
2103 bool FlowGraphOptimizer::TryInlineFloat64x2Constructor( 2053 bool AotOptimizer::TryInlineFloat64x2Constructor(
2104 StaticCallInstr* call, 2054 StaticCallInstr* call,
2105 MethodRecognizer::Kind recognized_kind) { 2055 MethodRecognizer::Kind recognized_kind) {
2106 if (FLAG_precompilation) { 2056 ASSERT(FLAG_precompilation);
rmacnak 2016/02/19 23:46:04 Keep comment
Florian Schneider 2016/02/23 15:27:02 Done.
2107 // Cannot handle unboxed instructions.
2108 return false;
2109 }
2110 if (!ShouldInlineSimd()) {
2111 return false;
2112 }
2113 if (recognized_kind == MethodRecognizer::kFloat64x2Zero) {
2114 Float64x2ZeroInstr* zero = new(Z) Float64x2ZeroInstr();
2115 ReplaceCall(call, zero);
2116 return true;
2117 } else if (recognized_kind == MethodRecognizer::kFloat64x2Splat) {
2118 Float64x2SplatInstr* splat =
2119 new(Z) Float64x2SplatInstr(
2120 new(Z) Value(call->ArgumentAt(1)), call->deopt_id());
2121 ReplaceCall(call, splat);
2122 return true;
2123 } else if (recognized_kind == MethodRecognizer::kFloat64x2Constructor) {
2124 Float64x2ConstructorInstr* con =
2125 new(Z) Float64x2ConstructorInstr(
2126 new(Z) Value(call->ArgumentAt(1)),
2127 new(Z) Value(call->ArgumentAt(2)),
2128 call->deopt_id());
2129 ReplaceCall(call, con);
2130 return true;
2131 } else if (recognized_kind == MethodRecognizer::kFloat64x2FromFloat32x4) {
2132 Float32x4ToFloat64x2Instr* cast =
2133 new(Z) Float32x4ToFloat64x2Instr(
2134 new(Z) Value(call->ArgumentAt(1)), call->deopt_id());
2135 ReplaceCall(call, cast);
2136 return true;
2137 }
2138 return false; 2057 return false;
2139 } 2058 }
2140 2059
2141 2060
2142 bool FlowGraphOptimizer::TryInlineInt32x4Constructor( 2061 bool AotOptimizer::TryInlineInt32x4Constructor(
2143 StaticCallInstr* call, 2062 StaticCallInstr* call,
2144 MethodRecognizer::Kind recognized_kind) { 2063 MethodRecognizer::Kind recognized_kind) {
2145 if (FLAG_precompilation) { 2064 ASSERT(FLAG_precompilation);
rmacnak 2016/02/19 23:46:03 Keep comment
Florian Schneider 2016/02/23 15:27:03 Done.
2146 // Cannot handle unboxed instructions.
2147 return false;
2148 }
2149 if (!ShouldInlineSimd()) {
2150 return false;
2151 }
2152 if (recognized_kind == MethodRecognizer::kInt32x4BoolConstructor) {
2153 Int32x4BoolConstructorInstr* con =
2154 new(Z) Int32x4BoolConstructorInstr(
2155 new(Z) Value(call->ArgumentAt(1)),
2156 new(Z) Value(call->ArgumentAt(2)),
2157 new(Z) Value(call->ArgumentAt(3)),
2158 new(Z) Value(call->ArgumentAt(4)),
2159 call->deopt_id());
2160 ReplaceCall(call, con);
2161 return true;
2162 } else if (recognized_kind == MethodRecognizer::kInt32x4FromFloat32x4Bits) {
2163 Float32x4ToInt32x4Instr* cast =
2164 new(Z) Float32x4ToInt32x4Instr(
2165 new(Z) Value(call->ArgumentAt(1)), call->deopt_id());
2166 ReplaceCall(call, cast);
2167 return true;
2168 } else if (recognized_kind == MethodRecognizer::kInt32x4Constructor) {
2169 Int32x4ConstructorInstr* con =
2170 new(Z) Int32x4ConstructorInstr(
2171 new(Z) Value(call->ArgumentAt(1)),
2172 new(Z) Value(call->ArgumentAt(2)),
2173 new(Z) Value(call->ArgumentAt(3)),
2174 new(Z) Value(call->ArgumentAt(4)),
2175 call->deopt_id());
2176 ReplaceCall(call, con);
2177 return true;
2178 }
2179 return false; 2065 return false;
2180 } 2066 }
2181 2067
2182 2068
2183 bool FlowGraphOptimizer::TryInlineFloat32x4Method( 2069 bool AotOptimizer::TryInlineFloat32x4Method(
2184 InstanceCallInstr* call, 2070 InstanceCallInstr* call,
2185 MethodRecognizer::Kind recognized_kind) { 2071 MethodRecognizer::Kind recognized_kind) {
2186 if (!ShouldInlineSimd()) { 2072 return false;
2187 return false;
2188 }
2189 ASSERT(call->HasICData());
2190 switch (recognized_kind) {
2191 case MethodRecognizer::kFloat32x4ShuffleX:
2192 case MethodRecognizer::kFloat32x4ShuffleY:
2193 case MethodRecognizer::kFloat32x4ShuffleZ:
2194 case MethodRecognizer::kFloat32x4ShuffleW:
2195 case MethodRecognizer::kFloat32x4GetSignMask:
2196 ASSERT(call->ic_data()->HasReceiverClassId(kFloat32x4Cid));
2197 ASSERT(call->ic_data()->HasOneTarget());
2198 return InlineFloat32x4Getter(call, recognized_kind);
2199
2200 case MethodRecognizer::kFloat32x4Equal:
2201 case MethodRecognizer::kFloat32x4GreaterThan:
2202 case MethodRecognizer::kFloat32x4GreaterThanOrEqual:
2203 case MethodRecognizer::kFloat32x4LessThan:
2204 case MethodRecognizer::kFloat32x4LessThanOrEqual:
2205 case MethodRecognizer::kFloat32x4NotEqual: {
2206 Definition* left = call->ArgumentAt(0);
2207 Definition* right = call->ArgumentAt(1);
2208 // Type check left.
2209 AddCheckClass(left,
2210 ICData::ZoneHandle(
2211 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
2212 call->deopt_id(),
2213 call->env(),
2214 call);
2215 // Replace call.
2216 Float32x4ComparisonInstr* cmp =
2217 new(Z) Float32x4ComparisonInstr(recognized_kind,
2218 new(Z) Value(left),
2219 new(Z) Value(right),
2220 call->deopt_id());
2221 ReplaceCall(call, cmp);
2222 return true;
2223 }
2224 case MethodRecognizer::kFloat32x4Min:
2225 case MethodRecognizer::kFloat32x4Max: {
2226 Definition* left = call->ArgumentAt(0);
2227 Definition* right = call->ArgumentAt(1);
2228 // Type check left.
2229 AddCheckClass(left,
2230 ICData::ZoneHandle(
2231 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
2232 call->deopt_id(),
2233 call->env(),
2234 call);
2235 Float32x4MinMaxInstr* minmax =
2236 new(Z) Float32x4MinMaxInstr(
2237 recognized_kind,
2238 new(Z) Value(left),
2239 new(Z) Value(right),
2240 call->deopt_id());
2241 ReplaceCall(call, minmax);
2242 return true;
2243 }
2244 case MethodRecognizer::kFloat32x4Scale: {
2245 Definition* left = call->ArgumentAt(0);
2246 Definition* right = call->ArgumentAt(1);
2247 // Type check left.
2248 AddCheckClass(left,
2249 ICData::ZoneHandle(
2250 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
2251 call->deopt_id(),
2252 call->env(),
2253 call);
2254 // Left and right values are swapped when handed to the instruction,
2255 // this is done so that the double value is loaded into the output
2256 // register and can be destroyed.
2257 Float32x4ScaleInstr* scale =
2258 new(Z) Float32x4ScaleInstr(recognized_kind,
2259 new(Z) Value(right),
2260 new(Z) Value(left),
2261 call->deopt_id());
2262 ReplaceCall(call, scale);
2263 return true;
2264 }
2265 case MethodRecognizer::kFloat32x4Sqrt:
2266 case MethodRecognizer::kFloat32x4ReciprocalSqrt:
2267 case MethodRecognizer::kFloat32x4Reciprocal: {
2268 Definition* left = call->ArgumentAt(0);
2269 AddCheckClass(left,
2270 ICData::ZoneHandle(
2271 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
2272 call->deopt_id(),
2273 call->env(),
2274 call);
2275 Float32x4SqrtInstr* sqrt =
2276 new(Z) Float32x4SqrtInstr(recognized_kind,
2277 new(Z) Value(left),
2278 call->deopt_id());
2279 ReplaceCall(call, sqrt);
2280 return true;
2281 }
2282 case MethodRecognizer::kFloat32x4WithX:
2283 case MethodRecognizer::kFloat32x4WithY:
2284 case MethodRecognizer::kFloat32x4WithZ:
2285 case MethodRecognizer::kFloat32x4WithW: {
2286 Definition* left = call->ArgumentAt(0);
2287 Definition* right = call->ArgumentAt(1);
2288 // Type check left.
2289 AddCheckClass(left,
2290 ICData::ZoneHandle(
2291 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
2292 call->deopt_id(),
2293 call->env(),
2294 call);
2295 Float32x4WithInstr* with = new(Z) Float32x4WithInstr(recognized_kind,
2296 new(Z) Value(left),
2297 new(Z) Value(right),
2298 call->deopt_id());
2299 ReplaceCall(call, with);
2300 return true;
2301 }
2302 case MethodRecognizer::kFloat32x4Absolute:
2303 case MethodRecognizer::kFloat32x4Negate: {
2304 Definition* left = call->ArgumentAt(0);
2305 // Type check left.
2306 AddCheckClass(left,
2307 ICData::ZoneHandle(
2308 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
2309 call->deopt_id(),
2310 call->env(),
2311 call);
2312 Float32x4ZeroArgInstr* zeroArg =
2313 new(Z) Float32x4ZeroArgInstr(
2314 recognized_kind, new(Z) Value(left), call->deopt_id());
2315 ReplaceCall(call, zeroArg);
2316 return true;
2317 }
2318 case MethodRecognizer::kFloat32x4Clamp: {
2319 Definition* left = call->ArgumentAt(0);
2320 Definition* lower = call->ArgumentAt(1);
2321 Definition* upper = call->ArgumentAt(2);
2322 // Type check left.
2323 AddCheckClass(left,
2324 ICData::ZoneHandle(
2325 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
2326 call->deopt_id(),
2327 call->env(),
2328 call);
2329 Float32x4ClampInstr* clamp = new(Z) Float32x4ClampInstr(
2330 new(Z) Value(left),
2331 new(Z) Value(lower),
2332 new(Z) Value(upper),
2333 call->deopt_id());
2334 ReplaceCall(call, clamp);
2335 return true;
2336 }
2337 case MethodRecognizer::kFloat32x4ShuffleMix:
2338 case MethodRecognizer::kFloat32x4Shuffle: {
2339 return InlineFloat32x4Getter(call, recognized_kind);
2340 }
2341 default:
2342 return false;
2343 }
2344 } 2073 }
2345 2074
2346 2075
2347 bool FlowGraphOptimizer::TryInlineFloat64x2Method( 2076 bool AotOptimizer::TryInlineFloat64x2Method(
2348 InstanceCallInstr* call, 2077 InstanceCallInstr* call,
2349 MethodRecognizer::Kind recognized_kind) { 2078 MethodRecognizer::Kind recognized_kind) {
2350 if (!ShouldInlineSimd()) { 2079 return false;
2351 return false;
2352 }
2353 ASSERT(call->HasICData());
2354 switch (recognized_kind) {
2355 case MethodRecognizer::kFloat64x2GetX:
2356 case MethodRecognizer::kFloat64x2GetY:
2357 ASSERT(call->ic_data()->HasReceiverClassId(kFloat64x2Cid));
2358 ASSERT(call->ic_data()->HasOneTarget());
2359 return InlineFloat64x2Getter(call, recognized_kind);
2360 case MethodRecognizer::kFloat64x2Negate:
2361 case MethodRecognizer::kFloat64x2Abs:
2362 case MethodRecognizer::kFloat64x2Sqrt:
2363 case MethodRecognizer::kFloat64x2GetSignMask: {
2364 Definition* left = call->ArgumentAt(0);
2365 // Type check left.
2366 AddCheckClass(left,
2367 ICData::ZoneHandle(
2368 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
2369 call->deopt_id(),
2370 call->env(),
2371 call);
2372 Float64x2ZeroArgInstr* zeroArg =
2373 new(Z) Float64x2ZeroArgInstr(
2374 recognized_kind, new(Z) Value(left), call->deopt_id());
2375 ReplaceCall(call, zeroArg);
2376 return true;
2377 }
2378 case MethodRecognizer::kFloat64x2Scale:
2379 case MethodRecognizer::kFloat64x2WithX:
2380 case MethodRecognizer::kFloat64x2WithY:
2381 case MethodRecognizer::kFloat64x2Min:
2382 case MethodRecognizer::kFloat64x2Max: {
2383 Definition* left = call->ArgumentAt(0);
2384 Definition* right = call->ArgumentAt(1);
2385 // Type check left.
2386 AddCheckClass(left,
2387 ICData::ZoneHandle(
2388 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
2389 call->deopt_id(),
2390 call->env(),
2391 call);
2392 Float64x2OneArgInstr* zeroArg =
2393 new(Z) Float64x2OneArgInstr(recognized_kind,
2394 new(Z) Value(left),
2395 new(Z) Value(right),
2396 call->deopt_id());
2397 ReplaceCall(call, zeroArg);
2398 return true;
2399 }
2400 default:
2401 return false;
2402 }
2403 } 2080 }
2404 2081
2405 2082
2406 bool FlowGraphOptimizer::TryInlineInt32x4Method( 2083 bool AotOptimizer::TryInlineInt32x4Method(
2407 InstanceCallInstr* call, 2084 InstanceCallInstr* call,
2408 MethodRecognizer::Kind recognized_kind) { 2085 MethodRecognizer::Kind recognized_kind) {
2409 if (!ShouldInlineSimd()) { 2086 return false;
2410 return false;
2411 }
2412 ASSERT(call->HasICData());
2413 switch (recognized_kind) {
2414 case MethodRecognizer::kInt32x4ShuffleMix:
2415 case MethodRecognizer::kInt32x4Shuffle:
2416 case MethodRecognizer::kInt32x4GetFlagX:
2417 case MethodRecognizer::kInt32x4GetFlagY:
2418 case MethodRecognizer::kInt32x4GetFlagZ:
2419 case MethodRecognizer::kInt32x4GetFlagW:
2420 case MethodRecognizer::kInt32x4GetSignMask:
2421 ASSERT(call->ic_data()->HasReceiverClassId(kInt32x4Cid));
2422 ASSERT(call->ic_data()->HasOneTarget());
2423 return InlineInt32x4Getter(call, recognized_kind);
2424
2425 case MethodRecognizer::kInt32x4Select: {
2426 Definition* mask = call->ArgumentAt(0);
2427 Definition* trueValue = call->ArgumentAt(1);
2428 Definition* falseValue = call->ArgumentAt(2);
2429 // Type check left.
2430 AddCheckClass(mask,
2431 ICData::ZoneHandle(
2432 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
2433 call->deopt_id(),
2434 call->env(),
2435 call);
2436 Int32x4SelectInstr* select = new(Z) Int32x4SelectInstr(
2437 new(Z) Value(mask),
2438 new(Z) Value(trueValue),
2439 new(Z) Value(falseValue),
2440 call->deopt_id());
2441 ReplaceCall(call, select);
2442 return true;
2443 }
2444 case MethodRecognizer::kInt32x4WithFlagX:
2445 case MethodRecognizer::kInt32x4WithFlagY:
2446 case MethodRecognizer::kInt32x4WithFlagZ:
2447 case MethodRecognizer::kInt32x4WithFlagW: {
2448 Definition* left = call->ArgumentAt(0);
2449 Definition* flag = call->ArgumentAt(1);
2450 // Type check left.
2451 AddCheckClass(left,
2452 ICData::ZoneHandle(
2453 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
2454 call->deopt_id(),
2455 call->env(),
2456 call);
2457 Int32x4SetFlagInstr* setFlag = new(Z) Int32x4SetFlagInstr(
2458 recognized_kind,
2459 new(Z) Value(left),
2460 new(Z) Value(flag),
2461 call->deopt_id());
2462 ReplaceCall(call, setFlag);
2463 return true;
2464 }
2465 default:
2466 return false;
2467 }
2468 } 2087 }
2469 2088
2470 2089
2471 // If type tests specified by 'ic_data' do not depend on type arguments, 2090 // If type tests specified by 'ic_data' do not depend on type arguments,
2472 // return mapping cid->result in 'results' (i : cid; i + 1: result). 2091 // return mapping cid->result in 'results' (i : cid; i + 1: result).
2473 // If all tests yield the same result, return it otherwise return Bool::null. 2092 // If all tests yield the same result, return it otherwise return Bool::null.
2474 // If no mapping is possible, 'results' is empty. 2093 // If no mapping is possible, 'results' is empty.
2475 // An instance-of test returning all same results can be converted to a class 2094 // An instance-of test returning all same results can be converted to a class
2476 // check. 2095 // check.
2477 RawBool* FlowGraphOptimizer::InstanceOfAsBool( 2096 RawBool* AotOptimizer::InstanceOfAsBool(
2478 const ICData& ic_data, 2097 const ICData& ic_data,
2479 const AbstractType& type, 2098 const AbstractType& type,
2480 ZoneGrowableArray<intptr_t>* results) const { 2099 ZoneGrowableArray<intptr_t>* results) const {
2481 ASSERT(results->is_empty()); 2100 ASSERT(results->is_empty());
2482 ASSERT(ic_data.NumArgsTested() == 1); // Unary checks only. 2101 ASSERT(ic_data.NumArgsTested() == 1); // Unary checks only.
2483 if (type.IsFunctionType() || type.IsDartFunctionType() || 2102 if (type.IsFunctionType() || type.IsDartFunctionType() ||
2484 !type.IsInstantiated() || type.IsMalformedOrMalbounded()) { 2103 !type.IsInstantiated() || type.IsMalformedOrMalbounded()) {
2485 return Bool::null(); 2104 return Bool::null();
2486 } 2105 }
2487 const Class& type_class = Class::Handle(Z, type.type_class()); 2106 const Class& type_class = Class::Handle(Z, type.type_class());
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
2526 if (is_subtype != prev.value()) { 2145 if (is_subtype != prev.value()) {
2527 results_differ = true; 2146 results_differ = true;
2528 } 2147 }
2529 } 2148 }
2530 } 2149 }
2531 return results_differ ? Bool::null() : prev.raw(); 2150 return results_differ ? Bool::null() : prev.raw();
2532 } 2151 }
2533 2152
2534 2153
2535 // Returns true if checking against this type is a direct class id comparison. 2154 // Returns true if checking against this type is a direct class id comparison.
2536 bool FlowGraphOptimizer::TypeCheckAsClassEquality(const AbstractType& type) { 2155 bool AotOptimizer::TypeCheckAsClassEquality(const AbstractType& type) {
2537 ASSERT(type.IsFinalized() && !type.IsMalformedOrMalbounded()); 2156 ASSERT(type.IsFinalized() && !type.IsMalformedOrMalbounded());
2538 // Requires CHA. 2157 // Requires CHA.
2539 if (!type.IsInstantiated()) return false; 2158 if (!type.IsInstantiated()) return false;
2540 // Function types have different type checking rules. 2159 // Function types have different type checking rules.
2541 if (type.IsFunctionType()) return false; 2160 if (type.IsFunctionType()) return false;
2542 const Class& type_class = Class::Handle(type.type_class()); 2161 const Class& type_class = Class::Handle(type.type_class());
2543 // Could be an interface check? 2162 // Could be an interface check?
2544 if (CHA::IsImplemented(type_class)) return false; 2163 if (CHA::IsImplemented(type_class)) return false;
2545 // Check if there are subclasses. 2164 // Check if there are subclasses.
2546 if (CHA::HasSubclasses(type_class)) { 2165 if (CHA::HasSubclasses(type_class)) {
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
2630 TryAddTest(results, kBigintCid, true); 2249 TryAddTest(results, kBigintCid, true);
2631 // Cannot deoptimize since all tests returning true have been added. 2250 // Cannot deoptimize since all tests returning true have been added.
2632 return false; 2251 return false;
2633 } 2252 }
2634 2253
2635 return true; // May deoptimize since we have not identified all 'true' tests. 2254 return true; // May deoptimize since we have not identified all 'true' tests.
2636 } 2255 }
2637 2256
2638 2257
2639 // TODO(srdjan): Use ICData to check if always true or false. 2258 // TODO(srdjan): Use ICData to check if always true or false.
2640 void FlowGraphOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) { 2259 void AotOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) {
2641 ASSERT(Token::IsTypeTestOperator(call->token_kind())); 2260 ASSERT(Token::IsTypeTestOperator(call->token_kind()));
2642 Definition* left = call->ArgumentAt(0); 2261 Definition* left = call->ArgumentAt(0);
2643 Definition* type_args = NULL; 2262 Definition* type_args = NULL;
2644 AbstractType& type = AbstractType::ZoneHandle(Z); 2263 AbstractType& type = AbstractType::ZoneHandle(Z);
2645 bool negate = false; 2264 bool negate = false;
2646 if (call->ArgumentCount() == 2) { 2265 if (call->ArgumentCount() == 2) {
2647 type_args = flow_graph()->constant_null(); 2266 type_args = flow_graph()->constant_null();
2648 if (call->function_name().raw() == 2267 if (call->function_name().raw() ==
2649 Library::PrivateCoreLibName(Symbols::_instanceOfNum()).raw()) { 2268 Library::PrivateCoreLibName(Symbols::_instanceOfNum()).raw()) {
2650 type = Type::Number(); 2269 type = Type::Number();
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
2738 new(Z) Value(left), 2357 new(Z) Value(left),
2739 new(Z) Value(type_args), 2358 new(Z) Value(type_args),
2740 type, 2359 type,
2741 negate, 2360 negate,
2742 call->deopt_id()); 2361 call->deopt_id());
2743 ReplaceCall(call, instance_of); 2362 ReplaceCall(call, instance_of);
2744 } 2363 }
2745 2364
2746 2365
2747 // TODO(srdjan): Apply optimizations as in ReplaceWithInstanceOf (TestCids). 2366 // TODO(srdjan): Apply optimizations as in ReplaceWithInstanceOf (TestCids).
2748 void FlowGraphOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) { 2367 void AotOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) {
2749 ASSERT(Token::IsTypeCastOperator(call->token_kind())); 2368 ASSERT(Token::IsTypeCastOperator(call->token_kind()));
2750 Definition* left = call->ArgumentAt(0); 2369 Definition* left = call->ArgumentAt(0);
2751 Definition* type_args = call->ArgumentAt(1); 2370 Definition* type_args = call->ArgumentAt(1);
2752 const AbstractType& type = 2371 const AbstractType& type =
2753 AbstractType::Cast(call->ArgumentAt(2)->AsConstant()->value()); 2372 AbstractType::Cast(call->ArgumentAt(2)->AsConstant()->value());
2754 ASSERT(!type.IsMalformedOrMalbounded()); 2373 ASSERT(!type.IsMalformedOrMalbounded());
2755 const ICData& unary_checks = 2374 const ICData& unary_checks =
2756 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks()); 2375 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks());
2757 if ((unary_checks.NumberOfChecks() > 0) && 2376 if ((unary_checks.NumberOfChecks() > 0) &&
2758 (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks)) { 2377 (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks)) {
(...skipping 22 matching lines...) Expand all
2781 new(Z) AssertAssignableInstr(call->token_pos(), 2400 new(Z) AssertAssignableInstr(call->token_pos(),
2782 new(Z) Value(left), 2401 new(Z) Value(left),
2783 new(Z) Value(type_args), 2402 new(Z) Value(type_args),
2784 type, 2403 type,
2785 dst_name, 2404 dst_name,
2786 call->deopt_id()); 2405 call->deopt_id());
2787 ReplaceCall(call, assert_as); 2406 ReplaceCall(call, assert_as);
2788 } 2407 }
2789 2408
2790 2409
2791 bool FlowGraphOptimizer::IsBlackListedForInlining(intptr_t call_deopt_id) { 2410 bool AotOptimizer::IsBlackListedForInlining(intptr_t call_deopt_id) {
2792 for (intptr_t i = 0; i < inlining_black_list_->length(); ++i) { 2411 for (intptr_t i = 0; i < inlining_black_list_->length(); ++i) {
2793 if ((*inlining_black_list_)[i] == call_deopt_id) return true; 2412 if ((*inlining_black_list_)[i] == call_deopt_id) return true;
2794 } 2413 }
2795 return false; 2414 return false;
2796 } 2415 }
2797 2416
2798 // Special optimizations when running in --noopt mode. 2417 // Special optimizations when running in --noopt mode.
2799 void FlowGraphOptimizer::InstanceCallNoopt(InstanceCallInstr* instr) { 2418 void AotOptimizer::InstanceCallNoopt(InstanceCallInstr* instr) {
2800 // TODO(srdjan): Investigate other attempts, as they are not allowed to 2419 // TODO(srdjan): Investigate other attempts, as they are not allowed to
2801 // deoptimize. 2420 // deoptimize.
2802 2421
2803 // Type test is special as it always gets converted into inlined code. 2422 // Type test is special as it always gets converted into inlined code.
2804 const Token::Kind op_kind = instr->token_kind(); 2423 const Token::Kind op_kind = instr->token_kind();
2805 if (Token::IsTypeTestOperator(op_kind)) { 2424 if (Token::IsTypeTestOperator(op_kind)) {
2806 ReplaceWithInstanceOf(instr); 2425 ReplaceWithInstanceOf(instr);
2807 return; 2426 return;
2808 } 2427 }
2809 if (Token::IsTypeCastOperator(op_kind)) { 2428 if (Token::IsTypeCastOperator(op_kind)) {
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
2928 new(Z) PolymorphicInstanceCallInstr(instr, ic_data, 2547 new(Z) PolymorphicInstanceCallInstr(instr, ic_data,
2929 /* with_checks = */ false); 2548 /* with_checks = */ false);
2930 instr->ReplaceWith(call, current_iterator()); 2549 instr->ReplaceWith(call, current_iterator());
2931 return; 2550 return;
2932 } 2551 }
2933 } 2552 }
2934 2553
2935 2554
2936 // Tries to optimize instance call by replacing it with a faster instruction 2555 // Tries to optimize instance call by replacing it with a faster instruction
2937 // (e.g, binary op, field load, ..). 2556 // (e.g, binary op, field load, ..).
2938 void FlowGraphOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { 2557 void AotOptimizer::VisitInstanceCall(InstanceCallInstr* instr) {
2939 if (FLAG_precompilation) { 2558 ASSERT(FLAG_precompilation);
2940 InstanceCallNoopt(instr); 2559 InstanceCallNoopt(instr);
2941 return;
2942 }
2943
2944 if (!instr->HasICData() || (instr->ic_data()->NumberOfUsedChecks() == 0)) {
2945 return;
2946 }
2947 const Token::Kind op_kind = instr->token_kind();
2948
2949 // Type test is special as it always gets converted into inlined code.
2950 if (Token::IsTypeTestOperator(op_kind)) {
2951 ReplaceWithInstanceOf(instr);
2952 return;
2953 }
2954
2955 if (Token::IsTypeCastOperator(op_kind)) {
2956 ReplaceWithTypeCast(instr);
2957 return;
2958 }
2959
2960 const ICData& unary_checks =
2961 ICData::ZoneHandle(Z, instr->ic_data()->AsUnaryClassChecks());
2962
2963 const intptr_t max_checks = (op_kind == Token::kEQ)
2964 ? FLAG_max_equality_polymorphic_checks
2965 : FLAG_max_polymorphic_checks;
2966 if ((unary_checks.NumberOfChecks() > max_checks) &&
2967 InstanceCallNeedsClassCheck(instr, RawFunction::kRegularFunction)) {
2968 // Too many checks, it will be megamorphic which needs unary checks.
2969 instr->set_ic_data(&unary_checks);
2970 return;
2971 }
2972
2973 if ((op_kind == Token::kASSIGN_INDEX) && TryReplaceWithIndexedOp(instr)) {
2974 return;
2975 }
2976 if ((op_kind == Token::kINDEX) && TryReplaceWithIndexedOp(instr)) {
2977 return;
2978 }
2979
2980 if (op_kind == Token::kEQ && TryReplaceWithEqualityOp(instr, op_kind)) {
2981 return;
2982 }
2983
2984 if (Token::IsRelationalOperator(op_kind) &&
2985 TryReplaceWithRelationalOp(instr, op_kind)) {
2986 return;
2987 }
2988
2989 if (Token::IsBinaryOperator(op_kind) &&
2990 TryReplaceWithBinaryOp(instr, op_kind)) {
2991 return;
2992 }
2993 if (Token::IsUnaryOperator(op_kind) &&
2994 TryReplaceWithUnaryOp(instr, op_kind)) {
2995 return;
2996 }
2997 if ((op_kind == Token::kGET) && TryInlineInstanceGetter(instr)) {
2998 return;
2999 }
3000 if ((op_kind == Token::kSET) &&
3001 TryInlineInstanceSetter(instr, unary_checks)) {
3002 return;
3003 }
3004 if (TryInlineInstanceMethod(instr)) {
3005 return;
3006 }
3007
3008 bool has_one_target = unary_checks.HasOneTarget();
3009
3010 if (has_one_target) {
3011 // Check if the single target is a polymorphic target, if it is,
3012 // we don't have one target.
3013 const Function& target =
3014 Function::Handle(Z, unary_checks.GetTargetAt(0));
3015 const bool polymorphic_target = MethodRecognizer::PolymorphicTarget(target);
3016 has_one_target = !polymorphic_target;
3017 }
3018
3019 if (has_one_target) {
3020 RawFunction::Kind function_kind =
3021 Function::Handle(Z, unary_checks.GetTargetAt(0)).kind();
3022 if (!InstanceCallNeedsClassCheck(instr, function_kind)) {
3023 PolymorphicInstanceCallInstr* call =
3024 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks,
3025 /* call_with_checks = */ false);
3026 instr->ReplaceWith(call, current_iterator());
3027 return;
3028 }
3029 }
3030
3031 if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) {
3032 bool call_with_checks;
3033 if (has_one_target && FLAG_polymorphic_with_deopt) {
3034 // Type propagation has not run yet, we cannot eliminate the check.
3035 AddReceiverCheck(instr);
3036 // Call can still deoptimize, do not detach environment from instr.
3037 call_with_checks = false;
3038 } else {
3039 call_with_checks = true;
3040 }
3041 PolymorphicInstanceCallInstr* call =
3042 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks,
3043 call_with_checks);
3044 instr->ReplaceWith(call, current_iterator());
3045 }
3046 } 2560 }
3047 2561
3048 2562
3049 void FlowGraphOptimizer::VisitStaticCall(StaticCallInstr* call) { 2563 void AotOptimizer::VisitStaticCall(StaticCallInstr* call) {
3050 if (!CanUnboxDouble()) { 2564 if (!CanUnboxDouble()) {
3051 return; 2565 return;
3052 } 2566 }
3053 MethodRecognizer::Kind recognized_kind = 2567 MethodRecognizer::Kind recognized_kind =
3054 MethodRecognizer::RecognizeKind(call->function()); 2568 MethodRecognizer::RecognizeKind(call->function());
3055 MathUnaryInstr::MathUnaryKind unary_kind; 2569 MathUnaryInstr::MathUnaryKind unary_kind;
3056 switch (recognized_kind) { 2570 switch (recognized_kind) {
3057 case MethodRecognizer::kMathSqrt: 2571 case MethodRecognizer::kMathSqrt:
3058 unary_kind = MathUnaryInstr::kSqrt; 2572 unary_kind = MathUnaryInstr::kSqrt;
3059 break; 2573 break;
3060 case MethodRecognizer::kMathSin: 2574 case MethodRecognizer::kMathSin:
3061 unary_kind = MathUnaryInstr::kSin; 2575 unary_kind = MathUnaryInstr::kSin;
3062 break; 2576 break;
3063 case MethodRecognizer::kMathCos: 2577 case MethodRecognizer::kMathCos:
3064 unary_kind = MathUnaryInstr::kCos; 2578 unary_kind = MathUnaryInstr::kCos;
3065 break; 2579 break;
3066 default: 2580 default:
3067 unary_kind = MathUnaryInstr::kIllegal; 2581 unary_kind = MathUnaryInstr::kIllegal;
3068 break; 2582 break;
3069 } 2583 }
3070 if (unary_kind != MathUnaryInstr::kIllegal) { 2584 if (unary_kind != MathUnaryInstr::kIllegal) {
3071 if (FLAG_precompilation) { 2585 ASSERT(FLAG_precompilation);
3072 // TODO(srdjan): Adapt MathUnaryInstr to allow tagged inputs as well. 2586 // TODO(srdjan): Adapt MathUnaryInstr to allow tagged inputs as well.
3073 return;
3074 }
3075 MathUnaryInstr* math_unary =
3076 new(Z) MathUnaryInstr(unary_kind,
3077 new(Z) Value(call->ArgumentAt(0)),
3078 call->deopt_id());
3079 ReplaceCall(call, math_unary);
3080 return; 2587 return;
3081 } 2588 }
2589
3082 switch (recognized_kind) { 2590 switch (recognized_kind) {
3083 case MethodRecognizer::kFloat32x4Zero: 2591 case MethodRecognizer::kFloat32x4Zero:
3084 case MethodRecognizer::kFloat32x4Splat: 2592 case MethodRecognizer::kFloat32x4Splat:
3085 case MethodRecognizer::kFloat32x4Constructor: 2593 case MethodRecognizer::kFloat32x4Constructor:
3086 case MethodRecognizer::kFloat32x4FromFloat64x2: 2594 case MethodRecognizer::kFloat32x4FromFloat64x2:
3087 TryInlineFloat32x4Constructor(call, recognized_kind); 2595 TryInlineFloat32x4Constructor(call, recognized_kind);
3088 break; 2596 break;
3089 case MethodRecognizer::kFloat64x2Constructor: 2597 case MethodRecognizer::kFloat64x2Constructor:
3090 case MethodRecognizer::kFloat64x2Zero: 2598 case MethodRecognizer::kFloat64x2Zero:
3091 case MethodRecognizer::kFloat64x2Splat: 2599 case MethodRecognizer::kFloat64x2Splat:
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
3147 } 2655 }
3148 } 2656 }
3149 break; 2657 break;
3150 } 2658 }
3151 case MethodRecognizer::kMathDoublePow: 2659 case MethodRecognizer::kMathDoublePow:
3152 case MethodRecognizer::kMathTan: 2660 case MethodRecognizer::kMathTan:
3153 case MethodRecognizer::kMathAsin: 2661 case MethodRecognizer::kMathAsin:
3154 case MethodRecognizer::kMathAcos: 2662 case MethodRecognizer::kMathAcos:
3155 case MethodRecognizer::kMathAtan: 2663 case MethodRecognizer::kMathAtan:
3156 case MethodRecognizer::kMathAtan2: { 2664 case MethodRecognizer::kMathAtan2: {
3157 if (FLAG_precompilation) { 2665 ASSERT(FLAG_precompilation);
3158 // No UnboxDouble instructons allowed. 2666 // No UnboxDouble instructions allowed.
3159 return; 2667 return;
3160 }
3161 // InvokeMathCFunctionInstr requires unboxed doubles. UnboxDouble
3162 // instructions contain type checks and conversions to double.
3163 ZoneGrowableArray<Value*>* args =
3164 new(Z) ZoneGrowableArray<Value*>(call->ArgumentCount());
3165 for (intptr_t i = 0; i < call->ArgumentCount(); i++) {
3166 args->Add(new(Z) Value(call->ArgumentAt(i)));
3167 }
3168 InvokeMathCFunctionInstr* invoke =
3169 new(Z) InvokeMathCFunctionInstr(args,
3170 call->deopt_id(),
3171 recognized_kind,
3172 call->token_pos());
3173 ReplaceCall(call, invoke);
3174 break;
3175 } 2668 }
3176 case MethodRecognizer::kDoubleFromInteger: { 2669 case MethodRecognizer::kDoubleFromInteger: {
3177 if (call->HasICData() && (call->ic_data()->NumberOfChecks() == 1)) { 2670 if (call->HasICData() && (call->ic_data()->NumberOfChecks() == 1)) {
3178 const ICData& ic_data = *call->ic_data(); 2671 const ICData& ic_data = *call->ic_data();
3179 if (CanUnboxDouble()) { 2672 if (CanUnboxDouble()) {
3180 if (ArgIsAlways(kSmiCid, ic_data, 1)) { 2673 if (ArgIsAlways(kSmiCid, ic_data, 1)) {
3181 Definition* arg = call->ArgumentAt(1); 2674 Definition* arg = call->ArgumentAt(1);
3182 AddCheckSmi(arg, call->deopt_id(), call->env(), call); 2675 AddCheckSmi(arg, call->deopt_id(), call->env(), call);
3183 ReplaceCall(call, 2676 ReplaceCall(call,
3184 new(Z) SmiToDoubleInstr(new(Z) Value(arg), 2677 new(Z) SmiToDoubleInstr(new(Z) Value(arg),
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
3220 default: 2713 default:
3221 break; 2714 break;
3222 } 2715 }
3223 } 2716 }
3224 } 2717 }
3225 } 2718 }
3226 } 2719 }
3227 } 2720 }
3228 2721
3229 2722
3230 void FlowGraphOptimizer::VisitStoreInstanceField( 2723 void AotOptimizer::VisitAllocateContext(AllocateContextInstr* instr) {
3231 StoreInstanceFieldInstr* instr) {
3232 if (instr->IsUnboxedStore()) {
3233 ASSERT(instr->is_potential_unboxed_initialization_);
3234 // Determine if this field should be unboxed based on the usage of getter
3235 // and setter functions: The heuristic requires that the setter has a
3236 // usage count of at least 1/kGetterSetterRatio of the getter usage count.
3237 // This is to avoid unboxing fields where the setter is never or rarely
3238 // executed.
3239 const Field& field = Field::ZoneHandle(Z, instr->field().raw());
3240 const String& field_name = String::Handle(Z, field.name());
3241 const Class& owner = Class::Handle(Z, field.owner());
3242 const Function& getter =
3243 Function::Handle(Z, owner.LookupGetterFunction(field_name));
3244 const Function& setter =
3245 Function::Handle(Z, owner.LookupSetterFunction(field_name));
3246 bool unboxed_field = false;
3247 if (!getter.IsNull() && !setter.IsNull()) {
3248 if (field.is_double_initialized()) {
3249 unboxed_field = true;
3250 } else if ((setter.usage_counter() > 0) &&
3251 ((FLAG_getter_setter_ratio * setter.usage_counter()) >=
3252 getter.usage_counter())) {
3253 unboxed_field = true;
3254 }
3255 }
3256 if (!unboxed_field) {
3257 // TODO(srdjan): Instead of aborting pass this field to the mutator thread
3258 // so that it can:
3259 // - set it to unboxed
3260 // - deoptimize dependent code.
3261 if (Compiler::IsBackgroundCompilation()) {
3262 isolate()->AddDeoptimizingBoxedField(field);
3263 Compiler::AbortBackgroundCompilation(Thread::kNoDeoptId);
3264 UNREACHABLE();
3265 }
3266 if (FLAG_trace_optimization || FLAG_trace_field_guards) {
3267 THR_Print("Disabling unboxing of %s\n", field.ToCString());
3268 if (!setter.IsNull()) {
3269 OS::Print(" setter usage count: %" Pd "\n", setter.usage_counter());
3270 }
3271 if (!getter.IsNull()) {
3272 OS::Print(" getter usage count: %" Pd "\n", getter.usage_counter());
3273 }
3274 }
3275 field.set_is_unboxing_candidate(false);
3276 field.DeoptimizeDependentCode();
3277 } else {
3278 FlowGraph::AddToGuardedFields(flow_graph_->guarded_fields(), &field);
3279 }
3280 }
3281 }
3282
3283
3284 void FlowGraphOptimizer::VisitAllocateContext(AllocateContextInstr* instr) {
3285 // Replace generic allocation with a sequence of inlined allocation and 2724 // Replace generic allocation with a sequence of inlined allocation and
3286 // explicit initalizing stores. 2725 // explicit initalizing stores.
3287 AllocateUninitializedContextInstr* replacement = 2726 AllocateUninitializedContextInstr* replacement =
3288 new AllocateUninitializedContextInstr(instr->token_pos(), 2727 new AllocateUninitializedContextInstr(instr->token_pos(),
3289 instr->num_context_variables()); 2728 instr->num_context_variables());
3290 instr->ReplaceWith(replacement, current_iterator()); 2729 instr->ReplaceWith(replacement, current_iterator());
3291 2730
3292 StoreInstanceFieldInstr* store = 2731 StoreInstanceFieldInstr* store =
3293 new(Z) StoreInstanceFieldInstr(Context::parent_offset(), 2732 new(Z) StoreInstanceFieldInstr(Context::parent_offset(),
3294 new Value(replacement), 2733 new Value(replacement),
(...skipping 14 matching lines...) Expand all
3309 instr->token_pos()); 2748 instr->token_pos());
3310 // Storing into uninitialized memory; remember to prevent dead store 2749 // Storing into uninitialized memory; remember to prevent dead store
3311 // elimination and ensure proper GC barrier. 2750 // elimination and ensure proper GC barrier.
3312 store->set_is_object_reference_initialization(true); 2751 store->set_is_object_reference_initialization(true);
3313 flow_graph_->InsertAfter(cursor, store, NULL, FlowGraph::kEffect); 2752 flow_graph_->InsertAfter(cursor, store, NULL, FlowGraph::kEffect);
3314 cursor = store; 2753 cursor = store;
3315 } 2754 }
3316 } 2755 }
3317 2756
3318 2757
3319 void FlowGraphOptimizer::VisitLoadCodeUnits(LoadCodeUnitsInstr* instr) { 2758 void AotOptimizer::VisitLoadCodeUnits(LoadCodeUnitsInstr* instr) {
3320 // TODO(zerny): Use kUnboxedUint32 once it is fully supported/optimized. 2759 // TODO(zerny): Use kUnboxedUint32 once it is fully supported/optimized.
3321 #if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_ARM) 2760 #if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_ARM)
3322 if (!instr->can_pack_into_smi()) 2761 if (!instr->can_pack_into_smi())
3323 instr->set_representation(kUnboxedMint); 2762 instr->set_representation(kUnboxedMint);
3324 #endif 2763 #endif
3325 } 2764 }
3326 2765
3327 2766
3328 bool FlowGraphOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr, 2767 bool AotOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr,
3329 const ICData& unary_ic_data, 2768 const ICData& unary_ic_data,
3330 bool allow_checks) { 2769 bool allow_checks) {
3331 ASSERT((unary_ic_data.NumberOfChecks() > 0) && 2770 ASSERT((unary_ic_data.NumberOfChecks() > 0) &&
3332 (unary_ic_data.NumArgsTested() == 1)); 2771 (unary_ic_data.NumArgsTested() == 1));
3333 if (I->flags().type_checks()) { 2772 if (I->flags().type_checks()) {
3334 // Checked mode setters are inlined like normal methods by conventional 2773 // Checked mode setters are inlined like normal methods by conventional
3335 // inlining. 2774 // inlining.
3336 return false; 2775 return false;
3337 } 2776 }
3338 2777
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
3406 2845
3407 // Discard the environment from the original instruction because the store 2846 // Discard the environment from the original instruction because the store
3408 // can't deoptimize. 2847 // can't deoptimize.
3409 instr->RemoveEnvironment(); 2848 instr->RemoveEnvironment();
3410 ReplaceCall(instr, store); 2849 ReplaceCall(instr, store);
3411 return true; 2850 return true;
3412 } 2851 }
3413 2852
3414 2853
3415 } // namespace dart 2854 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698