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

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: 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 DECLARE_FLAG(bool, guess_icdata_cid);
Ivan Posva 2016/02/19 01:07:49 Please move these to flag_list.h so that we keep r
Florian Schneider 2016/02/19 17:42:29 Done.
32 "Ratio of getter/setter usage used for double field unboxing heuristics"); 33 DECLARE_FLAG(int, max_polymorphic_checks);
33 DEFINE_FLAG(bool, guess_icdata_cid, true, 34 DECLARE_FLAG(int, max_equality_polymorphic_checks);
34 "Artificially create type feedback for arithmetic etc. operations" 35 DECLARE_FLAG(bool, merge_sin_cos);
35 " by guessing the other unknown argument cid"); 36 DECLARE_FLAG(bool, trace_optimization);
36 DEFINE_FLAG(int, max_polymorphic_checks, 4, 37 DECLARE_FLAG(bool, truncating_left_shift);
37 "Maximum number of polymorphic check, otherwise it is megamorphic."); 38 DECLARE_FLAG(bool, use_cha_deopt);
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); 39 DECLARE_FLAG(bool, precompilation);
49 DECLARE_FLAG(bool, polymorphic_with_deopt); 40 DECLARE_FLAG(bool, polymorphic_with_deopt);
50 DECLARE_FLAG(bool, trace_cha); 41 DECLARE_FLAG(bool, trace_cha);
51 DECLARE_FLAG(bool, trace_field_guards); 42 DECLARE_FLAG(bool, trace_field_guards);
52 43
53 // Quick access to the current isolate and zone. 44 // Quick access to the current isolate and zone.
54 #define I (isolate()) 45 #define I (isolate())
55 #define Z (zone()) 46 #define Z (zone())
56 47
57 static bool ShouldInlineSimd() { 48 static bool ShouldInlineSimd() {
58 return FlowGraphCompiler::SupportsUnboxedSimd128(); 49 return FlowGraphCompiler::SupportsUnboxedSimd128();
59 } 50 }
60 51
61 52
62 static bool CanUnboxDouble() { 53 static bool CanUnboxDouble() {
63 return FlowGraphCompiler::SupportsUnboxedDoubles(); 54 return FlowGraphCompiler::SupportsUnboxedDoubles();
64 } 55 }
65 56
66 57
67 static bool CanConvertUnboxedMintToDouble() { 58 static bool CanConvertUnboxedMintToDouble() {
68 return FlowGraphCompiler::CanConvertUnboxedMintToDouble(); 59 return FlowGraphCompiler::CanConvertUnboxedMintToDouble();
69 } 60 }
70 61
71 62
72 // Optimize instance calls using ICData. 63 // Optimize instance calls using ICData.
73 void FlowGraphOptimizer::ApplyICData() { 64 void AotOptimizer::ApplyICData() {
74 VisitBlocks(); 65 VisitBlocks();
75 } 66 }
76 67
77 68
78 void FlowGraphOptimizer::PopulateWithICData() { 69 void AotOptimizer::PopulateWithICData() {
79 ASSERT(current_iterator_ == NULL); 70 ASSERT(current_iterator_ == NULL);
80 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); 71 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator();
81 !block_it.Done(); 72 !block_it.Done();
82 block_it.Advance()) { 73 block_it.Advance()) {
83 ForwardInstructionIterator it(block_it.Current()); 74 ForwardInstructionIterator it(block_it.Current());
84 for (; !it.Done(); it.Advance()) { 75 for (; !it.Done(); it.Advance()) {
85 Instruction* instr = it.Current(); 76 Instruction* instr = it.Current();
86 if (instr->IsInstanceCall()) { 77 if (instr->IsInstanceCall()) {
87 InstanceCallInstr* call = instr->AsInstanceCall(); 78 InstanceCallInstr* call = instr->AsInstanceCall();
88 if (!call->HasICData()) { 79 if (!call->HasICData()) {
(...skipping 13 matching lines...) Expand all
102 } 93 }
103 } 94 }
104 95
105 96
106 // Optimize instance calls using cid. This is called after optimizer 97 // Optimize instance calls using cid. This is called after optimizer
107 // converted instance calls to instructions. Any remaining 98 // converted instance calls to instructions. Any remaining
108 // instance calls are either megamorphic calls, cannot be optimized or 99 // instance calls are either megamorphic calls, cannot be optimized or
109 // have no runtime type feedback collected. 100 // have no runtime type feedback collected.
110 // Attempts to convert an instance call (IC call) using propagated class-ids, 101 // 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. 102 // e.g., receiver class id, guarded-cid, or by guessing cid-s.
112 void FlowGraphOptimizer::ApplyClassIds() { 103 void AotOptimizer::ApplyClassIds() {
113 ASSERT(current_iterator_ == NULL); 104 ASSERT(current_iterator_ == NULL);
114 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); 105 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator();
115 !block_it.Done(); 106 !block_it.Done();
116 block_it.Advance()) { 107 block_it.Advance()) {
117 ForwardInstructionIterator it(block_it.Current()); 108 ForwardInstructionIterator it(block_it.Current());
118 current_iterator_ = ⁢ 109 current_iterator_ = ⁢
119 for (; !it.Done(); it.Advance()) { 110 for (; !it.Done(); it.Advance()) {
120 Instruction* instr = it.Current(); 111 Instruction* instr = it.Current();
121 if (instr->IsInstanceCall()) { 112 if (instr->IsInstanceCall()) {
122 InstanceCallInstr* call = instr->AsInstanceCall(); 113 InstanceCallInstr* call = instr->AsInstanceCall();
(...skipping 10 matching lines...) Expand all
133 } 124 }
134 } 125 }
135 126
136 127
137 // TODO(srdjan): Test/support other number types as well. 128 // TODO(srdjan): Test/support other number types as well.
138 static bool IsNumberCid(intptr_t cid) { 129 static bool IsNumberCid(intptr_t cid) {
139 return (cid == kSmiCid) || (cid == kDoubleCid); 130 return (cid == kSmiCid) || (cid == kDoubleCid);
140 } 131 }
141 132
142 133
143 bool FlowGraphOptimizer::TryCreateICData(InstanceCallInstr* call) { 134 static void GetUniqueDynamicTarget(Isolate* isolate,
135 const String& fname,
136 Object* function) {
137 UniqueFunctionsSet functions_set(
138 isolate->object_store()->unique_dynamic_targets());
139 ASSERT(fname.IsSymbol());
140 *function = functions_set.GetOrNull(fname);
141 ASSERT(functions_set.Release().raw() ==
142 isolate->object_store()->unique_dynamic_targets());
143 }
144
145
146 bool AotOptimizer::TryCreateICData(InstanceCallInstr* call) {
144 ASSERT(call->HasICData()); 147 ASSERT(call->HasICData());
145 if (call->ic_data()->NumberOfUsedChecks() > 0) { 148 if (call->ic_data()->NumberOfUsedChecks() > 0) {
146 // This occurs when an instance call has too many checks, will be converted 149 // This occurs when an instance call has too many checks, will be converted
147 // to megamorphic call. 150 // to megamorphic call.
148 return false; 151 return false;
149 } 152 }
150 GrowableArray<intptr_t> class_ids(call->ic_data()->NumArgsTested()); 153 GrowableArray<intptr_t> class_ids(call->ic_data()->NumArgsTested());
151 ASSERT(call->ic_data()->NumArgsTested() <= call->ArgumentCount()); 154 ASSERT(call->ic_data()->NumArgsTested() <= call->ArgumentCount());
152 for (intptr_t i = 0; i < call->ic_data()->NumArgsTested(); i++) { 155 for (intptr_t i = 0; i < call->ic_data()->NumArgsTested(); i++) {
153 class_ids.Add(call->PushArgumentAt(i)->value()->Type()->ToCid()); 156 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) { 213 if (class_ids.length() > 1) {
211 ic_data.AddCheck(class_ids, function); 214 ic_data.AddCheck(class_ids, function);
212 } else { 215 } else {
213 ASSERT(class_ids.length() == 1); 216 ASSERT(class_ids.length() == 1);
214 ic_data.AddReceiverCheck(class_ids[0], function); 217 ic_data.AddReceiverCheck(class_ids[0], function);
215 } 218 }
216 call->set_ic_data(&ic_data); 219 call->set_ic_data(&ic_data);
217 return true; 220 return true;
218 } 221 }
219 222
220 #ifdef DART_PRECOMPILER 223 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. 224 // Check if the target is unique.
224 Function& target_function = Function::Handle(Z); 225 Function& target_function = Function::Handle(Z);
225 Precompiler::GetUniqueDynamicTarget( 226 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. 227 // Calls with named arguments must be resolved/checked at runtime.
228 String& error_message = String::Handle(Z); 228 String& error_message = String::Handle(Z);
229 if (!target_function.IsNull() && 229 if (!target_function.IsNull() &&
230 !target_function.HasOptionalNamedParameters() && 230 !target_function.HasOptionalNamedParameters() &&
231 target_function.AreValidArgumentCounts(call->ArgumentCount(), 0, 231 target_function.AreValidArgumentCounts(call->ArgumentCount(), 0,
232 &error_message)) { 232 &error_message)) {
233 const intptr_t cid = Class::Handle(Z, target_function.Owner()).id(); 233 const intptr_t cid = Class::Handle(Z, target_function.Owner()).id();
234 const ICData& ic_data = ICData::ZoneHandle(Z, 234 const ICData& ic_data = ICData::ZoneHandle(Z,
235 ICData::NewFrom(*call->ic_data(), 1)); 235 ICData::NewFrom(*call->ic_data(), 1));
236 ic_data.AddReceiverCheck(cid, target_function); 236 ic_data.AddReceiverCheck(cid, target_function);
237 call->set_ic_data(&ic_data); 237 call->set_ic_data(&ic_data);
238 return true; 238 return true;
239 } 239 }
240 } 240 }
241 #endif
242 241
243 // Check if getter or setter in function's class and class is currently leaf. 242 // Check if getter or setter in function's class and class is currently leaf.
244 if (FLAG_guess_icdata_cid && 243 if (FLAG_guess_icdata_cid &&
245 ((call->token_kind() == Token::kGET) || 244 ((call->token_kind() == Token::kGET) ||
246 (call->token_kind() == Token::kSET))) { 245 (call->token_kind() == Token::kSET))) {
247 const Class& owner_class = Class::Handle(Z, function().Owner()); 246 const Class& owner_class = Class::Handle(Z, function().Owner());
248 if (!owner_class.is_abstract() && 247 if (!owner_class.is_abstract() &&
249 !CHA::HasSubclasses(owner_class) && 248 !CHA::HasSubclasses(owner_class) &&
250 !CHA::IsImplemented(owner_class)) { 249 !CHA::IsImplemented(owner_class)) {
251 const Array& args_desc_array = Array::Handle(Z, 250 const Array& args_desc_array = Array::Handle(Z,
(...skipping 11 matching lines...) Expand all
263 call->set_ic_data(&ic_data); 262 call->set_ic_data(&ic_data);
264 return true; 263 return true;
265 } 264 }
266 } 265 }
267 } 266 }
268 267
269 return false; 268 return false;
270 } 269 }
271 270
272 271
273 const ICData& FlowGraphOptimizer::TrySpecializeICData(const ICData& ic_data, 272 const ICData& AotOptimizer::TrySpecializeICData(const ICData& ic_data,
274 intptr_t cid) { 273 intptr_t cid) {
275 ASSERT(ic_data.NumArgsTested() == 1); 274 ASSERT(ic_data.NumArgsTested() == 1);
276 275
277 if ((ic_data.NumberOfUsedChecks() == 1) && ic_data.HasReceiverClassId(cid)) { 276 if ((ic_data.NumberOfUsedChecks() == 1) && ic_data.HasReceiverClassId(cid)) {
278 return ic_data; // Nothing to do 277 return ic_data; // Nothing to do
279 } 278 }
280 279
281 const Function& function = 280 const Function& function =
282 Function::Handle(Z, ic_data.GetTargetForReceiverClassId(cid)); 281 Function::Handle(Z, ic_data.GetTargetForReceiverClassId(cid));
283 // TODO(fschneider): Try looking up the function on the class if it is 282 // TODO(fschneider): Try looking up the function on the class if it is
284 // not found in the ICData. 283 // not found in the ICData.
285 if (!function.IsNull()) { 284 if (!function.IsNull()) {
286 const ICData& new_ic_data = ICData::ZoneHandle(Z, ICData::New( 285 const ICData& new_ic_data = ICData::ZoneHandle(Z, ICData::New(
287 Function::Handle(Z, ic_data.Owner()), 286 Function::Handle(Z, ic_data.Owner()),
288 String::Handle(Z, ic_data.target_name()), 287 String::Handle(Z, ic_data.target_name()),
289 Object::empty_array(), // Dummy argument descriptor. 288 Object::empty_array(), // Dummy argument descriptor.
290 ic_data.deopt_id(), 289 ic_data.deopt_id(),
291 ic_data.NumArgsTested())); 290 ic_data.NumArgsTested()));
292 new_ic_data.SetDeoptReasons(ic_data.DeoptReasons()); 291 new_ic_data.SetDeoptReasons(ic_data.DeoptReasons());
293 new_ic_data.AddReceiverCheck(cid, function); 292 new_ic_data.AddReceiverCheck(cid, function);
294 return new_ic_data; 293 return new_ic_data;
295 } 294 }
296 295
297 return ic_data; 296 return ic_data;
298 } 297 }
299 298
300 299
301 void FlowGraphOptimizer::SpecializePolymorphicInstanceCall( 300 void AotOptimizer::SpecializePolymorphicInstanceCall(
302 PolymorphicInstanceCallInstr* call) { 301 PolymorphicInstanceCallInstr* call) {
303 if (!FLAG_polymorphic_with_deopt) { 302 if (!FLAG_polymorphic_with_deopt) {
304 // Specialization adds receiver checks which can lead to deoptimization. 303 // Specialization adds receiver checks which can lead to deoptimization.
305 return; 304 return;
306 } 305 }
307 if (!call->with_checks()) { 306 if (!call->with_checks()) {
308 return; // Already specialized. 307 return; // Already specialized.
309 } 308 }
310 309
311 const intptr_t receiver_cid = 310 const intptr_t receiver_cid =
(...skipping 28 matching lines...) Expand all
340 339
341 static bool IsPositiveOrZeroSmiConst(Definition* d) { 340 static bool IsPositiveOrZeroSmiConst(Definition* d) {
342 ConstantInstr* const_instr = d->AsConstant(); 341 ConstantInstr* const_instr = d->AsConstant();
343 if ((const_instr != NULL) && (const_instr->value().IsSmi())) { 342 if ((const_instr != NULL) && (const_instr->value().IsSmi())) {
344 return Smi::Cast(const_instr->value()).Value() >= 0; 343 return Smi::Cast(const_instr->value()).Value() >= 0;
345 } 344 }
346 return false; 345 return false;
347 } 346 }
348 347
349 348
350 void FlowGraphOptimizer::OptimizeLeftShiftBitAndSmiOp( 349 void AotOptimizer::OptimizeLeftShiftBitAndSmiOp(
351 Definition* bit_and_instr, 350 Definition* bit_and_instr,
352 Definition* left_instr, 351 Definition* left_instr,
353 Definition* right_instr) { 352 Definition* right_instr) {
354 ASSERT(bit_and_instr != NULL); 353 ASSERT(bit_and_instr != NULL);
355 ASSERT((left_instr != NULL) && (right_instr != NULL)); 354 ASSERT((left_instr != NULL) && (right_instr != NULL));
356 355
357 // Check for pattern, smi_shift_left must be single-use. 356 // Check for pattern, smi_shift_left must be single-use.
358 bool is_positive_or_zero = IsPositiveOrZeroSmiConst(left_instr); 357 bool is_positive_or_zero = IsPositiveOrZeroSmiConst(left_instr);
359 if (!is_positive_or_zero) { 358 if (!is_positive_or_zero) {
360 is_positive_or_zero = IsPositiveOrZeroSmiConst(right_instr); 359 is_positive_or_zero = IsPositiveOrZeroSmiConst(right_instr);
(...skipping 17 matching lines...) Expand all
378 BinarySmiOpInstr* smi_op = new(Z) BinarySmiOpInstr( 377 BinarySmiOpInstr* smi_op = new(Z) BinarySmiOpInstr(
379 Token::kBIT_AND, 378 Token::kBIT_AND,
380 new(Z) Value(left_instr), 379 new(Z) Value(left_instr),
381 new(Z) Value(right_instr), 380 new(Z) Value(right_instr),
382 Thread::kNoDeoptId); // BIT_AND cannot deoptimize. 381 Thread::kNoDeoptId); // BIT_AND cannot deoptimize.
383 bit_and_instr->ReplaceWith(smi_op, current_iterator()); 382 bit_and_instr->ReplaceWith(smi_op, current_iterator());
384 } 383 }
385 } 384 }
386 385
387 386
388 void FlowGraphOptimizer::AppendExtractNthOutputForMerged(Definition* instr, 387 void AotOptimizer::AppendExtractNthOutputForMerged(Definition* instr,
389 intptr_t index, 388 intptr_t index,
390 Representation rep, 389 Representation rep,
391 intptr_t cid) { 390 intptr_t cid) {
392 ExtractNthOutputInstr* extract = 391 ExtractNthOutputInstr* extract =
393 new(Z) ExtractNthOutputInstr(new(Z) Value(instr), index, rep, cid); 392 new(Z) ExtractNthOutputInstr(new(Z) Value(instr), index, rep, cid);
394 instr->ReplaceUsesWith(extract); 393 instr->ReplaceUsesWith(extract);
395 flow_graph()->InsertAfter(instr, extract, NULL, FlowGraph::kValue); 394 flow_graph()->InsertAfter(instr, extract, NULL, FlowGraph::kValue);
396 } 395 }
397 396
398 397
399 // Dart: 398 // Dart:
400 // var x = d % 10; 399 // var x = d % 10;
401 // var y = d ~/ 10; 400 // var y = d ~/ 10;
402 // var z = x + y; 401 // var z = x + y;
403 // 402 //
404 // IL: 403 // IL:
405 // v4 <- %(v2, v3) 404 // v4 <- %(v2, v3)
406 // v5 <- ~/(v2, v3) 405 // v5 <- ~/(v2, v3)
407 // v6 <- +(v4, v5) 406 // v6 <- +(v4, v5)
408 // 407 //
409 // IL optimized: 408 // IL optimized:
410 // v4 <- DIVMOD(v2, v3); 409 // v4 <- DIVMOD(v2, v3);
411 // v5 <- LoadIndexed(v4, 0); // ~/ result 410 // v5 <- LoadIndexed(v4, 0); // ~/ result
412 // v6 <- LoadIndexed(v4, 1); // % result 411 // v6 <- LoadIndexed(v4, 1); // % result
413 // v7 <- +(v5, v6) 412 // v7 <- +(v5, v6)
414 // Because of the environment it is important that merged instruction replaces 413 // Because of the environment it is important that merged instruction replaces
415 // first original instruction encountered. 414 // first original instruction encountered.
416 void FlowGraphOptimizer::TryMergeTruncDivMod( 415 void AotOptimizer::TryMergeTruncDivMod(
417 GrowableArray<BinarySmiOpInstr*>* merge_candidates) { 416 GrowableArray<BinarySmiOpInstr*>* merge_candidates) {
418 if (merge_candidates->length() < 2) { 417 if (merge_candidates->length() < 2) {
419 // Need at least a TRUNCDIV and a MOD. 418 // Need at least a TRUNCDIV and a MOD.
420 return; 419 return;
421 } 420 }
422 for (intptr_t i = 0; i < merge_candidates->length(); i++) { 421 for (intptr_t i = 0; i < merge_candidates->length(); i++) {
423 BinarySmiOpInstr* curr_instr = (*merge_candidates)[i]; 422 BinarySmiOpInstr* curr_instr = (*merge_candidates)[i];
424 if (curr_instr == NULL) { 423 if (curr_instr == NULL) {
425 // Instruction was merged already. 424 // Instruction was merged already.
426 continue; 425 continue;
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
467 // more candidates are possible. 466 // more candidates are possible.
468 // TODO(srdjan): Allow merging of trunc-div/mod into truncDivMod. 467 // TODO(srdjan): Allow merging of trunc-div/mod into truncDivMod.
469 break; 468 break;
470 } 469 }
471 } 470 }
472 } 471 }
473 } 472 }
474 473
475 474
476 // Tries to merge MathUnary operations, in this case sinus and cosinus. 475 // Tries to merge MathUnary operations, in this case sinus and cosinus.
477 void FlowGraphOptimizer::TryMergeMathUnary( 476 void AotOptimizer::TryMergeMathUnary(
478 GrowableArray<MathUnaryInstr*>* merge_candidates) { 477 GrowableArray<MathUnaryInstr*>* merge_candidates) {
479 if (!FlowGraphCompiler::SupportsSinCos() || !CanUnboxDouble() || 478 if (!FlowGraphCompiler::SupportsSinCos() || !CanUnboxDouble() ||
480 !FLAG_merge_sin_cos) { 479 !FLAG_merge_sin_cos) {
481 return; 480 return;
482 } 481 }
483 if (merge_candidates->length() < 2) { 482 if (merge_candidates->length() < 2) {
484 // Need at least a SIN and a COS. 483 // Need at least a SIN and a COS.
485 return; 484 return;
486 } 485 }
487 for (intptr_t i = 0; i < merge_candidates->length(); i++) { 486 for (intptr_t i = 0; i < merge_candidates->length(); i++) {
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
528 break; 527 break;
529 } 528 }
530 } 529 }
531 } 530 }
532 } 531 }
533 532
534 533
535 // Optimize (a << b) & c pattern: if c is a positive Smi or zero, then the 534 // 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. 535 // shift can be a truncating Smi shift-left and result is always Smi.
537 // Merging occurs only per basic-block. 536 // Merging occurs only per basic-block.
538 void FlowGraphOptimizer::TryOptimizePatterns() { 537 void AotOptimizer::TryOptimizePatterns() {
539 if (!FLAG_truncating_left_shift) return; 538 if (!FLAG_truncating_left_shift) return;
540 ASSERT(current_iterator_ == NULL); 539 ASSERT(current_iterator_ == NULL);
541 GrowableArray<BinarySmiOpInstr*> div_mod_merge; 540 GrowableArray<BinarySmiOpInstr*> div_mod_merge;
542 GrowableArray<MathUnaryInstr*> sin_cos_merge; 541 GrowableArray<MathUnaryInstr*> sin_cos_merge;
543 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); 542 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator();
544 !block_it.Done(); 543 !block_it.Done();
545 block_it.Advance()) { 544 block_it.Advance()) {
546 // Merging only per basic-block. 545 // Merging only per basic-block.
547 div_mod_merge.Clear(); 546 div_mod_merge.Clear();
548 sin_cos_merge.Clear(); 547 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. 713 // Unboxed double operation can't handle case of two smis.
715 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) { 714 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) {
716 return false; 715 return false;
717 } 716 }
718 717
719 // Check that it have seen only smis and doubles. 718 // Check that it have seen only smis and doubles.
720 return HasTwoDoubleOrSmi(ic_data); 719 return HasTwoDoubleOrSmi(ic_data);
721 } 720 }
722 721
723 722
724 void FlowGraphOptimizer::ReplaceCall(Definition* call, 723 void AotOptimizer::ReplaceCall(Definition* call,
725 Definition* replacement) { 724 Definition* replacement) {
726 // Remove the original push arguments. 725 // Remove the original push arguments.
727 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { 726 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
728 PushArgumentInstr* push = call->PushArgumentAt(i); 727 PushArgumentInstr* push = call->PushArgumentAt(i);
729 push->ReplaceUsesWith(push->value()->definition()); 728 push->ReplaceUsesWith(push->value()->definition());
730 push->RemoveFromGraph(); 729 push->RemoveFromGraph();
731 } 730 }
732 call->ReplaceWith(replacement, current_iterator()); 731 call->ReplaceWith(replacement, current_iterator());
733 } 732 }
734 733
735 734
736 void FlowGraphOptimizer::AddCheckSmi(Definition* to_check, 735 void AotOptimizer::AddCheckSmi(Definition* to_check,
737 intptr_t deopt_id, 736 intptr_t deopt_id,
738 Environment* deopt_environment, 737 Environment* deopt_environment,
739 Instruction* insert_before) { 738 Instruction* insert_before) {
740 if (to_check->Type()->ToCid() != kSmiCid) { 739 if (to_check->Type()->ToCid() != kSmiCid) {
741 InsertBefore(insert_before, 740 InsertBefore(insert_before,
742 new(Z) CheckSmiInstr(new(Z) Value(to_check), 741 new(Z) CheckSmiInstr(new(Z) Value(to_check),
743 deopt_id, 742 deopt_id,
744 insert_before->token_pos()), 743 insert_before->token_pos()),
745 deopt_environment, 744 deopt_environment,
746 FlowGraph::kEffect); 745 FlowGraph::kEffect);
747 } 746 }
748 } 747 }
749 748
750 749
751 Instruction* FlowGraphOptimizer::GetCheckClass(Definition* to_check, 750 Instruction* AotOptimizer::GetCheckClass(Definition* to_check,
752 const ICData& unary_checks, 751 const ICData& unary_checks,
753 intptr_t deopt_id, 752 intptr_t deopt_id,
754 TokenPosition token_pos) { 753 TokenPosition token_pos) {
755 if ((unary_checks.NumberOfUsedChecks() == 1) && 754 if ((unary_checks.NumberOfUsedChecks() == 1) &&
756 unary_checks.HasReceiverClassId(kSmiCid)) { 755 unary_checks.HasReceiverClassId(kSmiCid)) {
757 return new(Z) CheckSmiInstr(new(Z) Value(to_check), 756 return new(Z) CheckSmiInstr(new(Z) Value(to_check),
758 deopt_id, 757 deopt_id,
759 token_pos); 758 token_pos);
760 } 759 }
761 return new(Z) CheckClassInstr( 760 return new(Z) CheckClassInstr(
762 new(Z) Value(to_check), deopt_id, unary_checks, token_pos); 761 new(Z) Value(to_check), deopt_id, unary_checks, token_pos);
763 } 762 }
764 763
765 764
766 void FlowGraphOptimizer::AddCheckClass(Definition* to_check, 765 void AotOptimizer::AddCheckClass(Definition* to_check,
767 const ICData& unary_checks, 766 const ICData& unary_checks,
768 intptr_t deopt_id, 767 intptr_t deopt_id,
769 Environment* deopt_environment, 768 Environment* deopt_environment,
770 Instruction* insert_before) { 769 Instruction* insert_before) {
771 // Type propagation has not run yet, we cannot eliminate the check. 770 // Type propagation has not run yet, we cannot eliminate the check.
772 Instruction* check = GetCheckClass( 771 Instruction* check = GetCheckClass(
773 to_check, unary_checks, deopt_id, insert_before->token_pos()); 772 to_check, unary_checks, deopt_id, insert_before->token_pos());
774 InsertBefore(insert_before, check, deopt_environment, FlowGraph::kEffect); 773 InsertBefore(insert_before, check, deopt_environment, FlowGraph::kEffect);
775 } 774 }
776 775
777 776
778 void FlowGraphOptimizer::AddReceiverCheck(InstanceCallInstr* call) { 777 void AotOptimizer::AddReceiverCheck(InstanceCallInstr* call) {
779 AddCheckClass(call->ArgumentAt(0), 778 AddCheckClass(call->ArgumentAt(0),
780 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks()), 779 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks()),
781 call->deopt_id(), 780 call->deopt_id(),
782 call->env(), 781 call->env(),
783 call); 782 call);
784 } 783 }
785 784
786 785
787 static bool ArgIsAlways(intptr_t cid, 786 static bool ArgIsAlways(intptr_t cid,
788 const ICData& ic_data, 787 const ICData& ic_data,
789 intptr_t arg_number) { 788 intptr_t arg_number) {
790 ASSERT(ic_data.NumArgsTested() > arg_number); 789 ASSERT(ic_data.NumArgsTested() > arg_number);
791 if (ic_data.NumberOfUsedChecks() == 0) { 790 if (ic_data.NumberOfUsedChecks() == 0) {
792 return false; 791 return false;
793 } 792 }
794 const intptr_t num_checks = ic_data.NumberOfChecks(); 793 const intptr_t num_checks = ic_data.NumberOfChecks();
795 for (intptr_t i = 0; i < num_checks; i++) { 794 for (intptr_t i = 0; i < num_checks; i++) {
796 if (ic_data.IsUsedAt(i) && ic_data.GetClassIdAt(i, arg_number) != cid) { 795 if (ic_data.IsUsedAt(i) && ic_data.GetClassIdAt(i, arg_number) != cid) {
797 return false; 796 return false;
798 } 797 }
799 } 798 }
800 return true; 799 return true;
801 } 800 }
802 801
803 802
804 bool FlowGraphOptimizer::TryReplaceWithIndexedOp(InstanceCallInstr* call) { 803 bool AotOptimizer::TryReplaceWithIndexedOp(InstanceCallInstr* call) {
805 // Check for monomorphic IC data. 804 // Check for monomorphic IC data.
806 if (!call->HasICData()) return false; 805 if (!call->HasICData()) return false;
807 const ICData& ic_data = 806 const ICData& ic_data =
808 ICData::Handle(Z, call->ic_data()->AsUnaryClassChecks()); 807 ICData::Handle(Z, call->ic_data()->AsUnaryClassChecks());
809 if (ic_data.NumberOfChecks() != 1) { 808 if (ic_data.NumberOfChecks() != 1) {
810 return false; 809 return false;
811 } 810 }
812 return TryReplaceInstanceCallWithInline(call); 811 return TryReplaceInstanceCallWithInline(call);
813 } 812 }
814 813
(...skipping 11 matching lines...) Expand all
826 } else { 825 } else {
827 return d->IsStringFromCharCode(); 826 return d->IsStringFromCharCode();
828 } 827 }
829 } 828 }
830 829
831 830
832 // Returns true if the string comparison was converted into char-code 831 // Returns true if the string comparison was converted into char-code
833 // comparison. Conversion is only possible for strings of length one. 832 // 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. 833 // E.g., detect str[x] == "x"; and use an integer comparison of char-codes.
835 // TODO(srdjan): Expand for two-byte and external strings. 834 // TODO(srdjan): Expand for two-byte and external strings.
836 bool FlowGraphOptimizer::TryStringLengthOneEquality(InstanceCallInstr* call, 835 bool AotOptimizer::TryStringLengthOneEquality(InstanceCallInstr* call,
837 Token::Kind op_kind) { 836 Token::Kind op_kind) {
838 ASSERT(HasOnlyTwoOf(*call->ic_data(), kOneByteStringCid)); 837 ASSERT(HasOnlyTwoOf(*call->ic_data(), kOneByteStringCid));
839 // Check that left and right are length one strings (either string constants 838 // Check that left and right are length one strings (either string constants
840 // or results of string-from-char-code. 839 // or results of string-from-char-code.
841 Definition* left = call->ArgumentAt(0); 840 Definition* left = call->ArgumentAt(0);
842 Definition* right = call->ArgumentAt(1); 841 Definition* right = call->ArgumentAt(1);
843 Value* left_val = NULL; 842 Value* left_val = NULL;
844 Definition* to_remove_left = NULL; 843 Definition* to_remove_left = NULL;
845 if (IsLengthOneString(right)) { 844 if (IsLengthOneString(right)) {
846 // Swap, since we know that both arguments are strings 845 // 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(); 912 to_remove_right->RemoveFromGraph();
914 } 913 }
915 return true; 914 return true;
916 } 915 }
917 return false; 916 return false;
918 } 917 }
919 918
920 919
921 static bool SmiFitsInDouble() { return kSmiBits < 53; } 920 static bool SmiFitsInDouble() { return kSmiBits < 53; }
922 921
923 bool FlowGraphOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call, 922 bool AotOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call,
924 Token::Kind op_kind) { 923 Token::Kind op_kind) {
925 const ICData& ic_data = *call->ic_data(); 924 const ICData& ic_data = *call->ic_data();
926 ASSERT(ic_data.NumArgsTested() == 2); 925 ASSERT(ic_data.NumArgsTested() == 2);
927 926
928 ASSERT(call->ArgumentCount() == 2); 927 ASSERT(call->ArgumentCount() == 2);
929 Definition* left = call->ArgumentAt(0); 928 Definition* left = call->ArgumentAt(0);
930 Definition* right = call->ArgumentAt(1); 929 Definition* right = call->ArgumentAt(1);
931 930
932 intptr_t cid = kIllegalCid; 931 intptr_t cid = kIllegalCid;
933 if (HasOnlyTwoOf(ic_data, kOneByteStringCid)) { 932 if (HasOnlyTwoOf(ic_data, kOneByteStringCid)) {
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
1022 op_kind, 1021 op_kind,
1023 new(Z) Value(left), 1022 new(Z) Value(left),
1024 new(Z) Value(right), 1023 new(Z) Value(right),
1025 cid, 1024 cid,
1026 call->deopt_id()); 1025 call->deopt_id());
1027 ReplaceCall(call, comp); 1026 ReplaceCall(call, comp);
1028 return true; 1027 return true;
1029 } 1028 }
1030 1029
1031 1030
1032 bool FlowGraphOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call, 1031 bool AotOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call,
1033 Token::Kind op_kind) { 1032 Token::Kind op_kind) {
1034 const ICData& ic_data = *call->ic_data(); 1033 const ICData& ic_data = *call->ic_data();
1035 ASSERT(ic_data.NumArgsTested() == 2); 1034 ASSERT(ic_data.NumArgsTested() == 2);
1036 1035
1037 ASSERT(call->ArgumentCount() == 2); 1036 ASSERT(call->ArgumentCount() == 2);
1038 Definition* left = call->ArgumentAt(0); 1037 Definition* left = call->ArgumentAt(0);
1039 Definition* right = call->ArgumentAt(1); 1038 Definition* right = call->ArgumentAt(1);
1040 1039
1041 intptr_t cid = kIllegalCid; 1040 intptr_t cid = kIllegalCid;
1042 if (HasOnlyTwoOf(ic_data, kSmiCid)) { 1041 if (HasOnlyTwoOf(ic_data, kSmiCid)) {
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
1084 op_kind, 1083 op_kind,
1085 new(Z) Value(left), 1084 new(Z) Value(left),
1086 new(Z) Value(right), 1085 new(Z) Value(right),
1087 cid, 1086 cid,
1088 call->deopt_id()); 1087 call->deopt_id());
1089 ReplaceCall(call, comp); 1088 ReplaceCall(call, comp);
1090 return true; 1089 return true;
1091 } 1090 }
1092 1091
1093 1092
1094 bool FlowGraphOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call, 1093 bool AotOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call,
1095 Token::Kind op_kind) { 1094 Token::Kind op_kind) {
1096 intptr_t operands_type = kIllegalCid; 1095 intptr_t operands_type = kIllegalCid;
1097 ASSERT(call->HasICData()); 1096 ASSERT(call->HasICData());
1098 const ICData& ic_data = *call->ic_data(); 1097 const ICData& ic_data = *call->ic_data();
1099 switch (op_kind) { 1098 switch (op_kind) {
1100 case Token::kADD: 1099 case Token::kADD:
1101 case Token::kSUB: 1100 case Token::kSUB:
1102 case Token::kMUL: 1101 case Token::kMUL:
1103 if (HasOnlyTwoOf(ic_data, kSmiCid)) { 1102 if (HasOnlyTwoOf(ic_data, kSmiCid)) {
1104 // Don't generate smi code if the IC data is marked because 1103 // 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, 1292 op_kind,
1294 new(Z) Value(left), 1293 new(Z) Value(left),
1295 new(Z) Value(right), 1294 new(Z) Value(right),
1296 call->deopt_id()); 1295 call->deopt_id());
1297 ReplaceCall(call, bin_op); 1296 ReplaceCall(call, bin_op);
1298 } 1297 }
1299 return true; 1298 return true;
1300 } 1299 }
1301 1300
1302 1301
1303 bool FlowGraphOptimizer::TryReplaceWithUnaryOp(InstanceCallInstr* call, 1302 bool AotOptimizer::TryReplaceWithUnaryOp(InstanceCallInstr* call,
1304 Token::Kind op_kind) { 1303 Token::Kind op_kind) {
1305 ASSERT(call->ArgumentCount() == 1); 1304 ASSERT(call->ArgumentCount() == 1);
1306 Definition* input = call->ArgumentAt(0); 1305 Definition* input = call->ArgumentAt(0);
1307 Definition* unary_op = NULL; 1306 Definition* unary_op = NULL;
1308 if (HasOnlyOneSmi(*call->ic_data())) { 1307 if (HasOnlyOneSmi(*call->ic_data())) {
1309 InsertBefore(call, 1308 InsertBefore(call,
1310 new(Z) CheckSmiInstr(new(Z) Value(input), 1309 new(Z) CheckSmiInstr(new(Z) Value(input),
1311 call->deopt_id(), 1310 call->deopt_id(),
1312 call->token_pos()), 1311 call->token_pos()),
1313 call->env(), 1312 call->env(),
(...skipping 14 matching lines...) Expand all
1328 } else { 1327 } else {
1329 return false; 1328 return false;
1330 } 1329 }
1331 ASSERT(unary_op != NULL); 1330 ASSERT(unary_op != NULL);
1332 ReplaceCall(call, unary_op); 1331 ReplaceCall(call, unary_op);
1333 return true; 1332 return true;
1334 } 1333 }
1335 1334
1336 1335
1337 // Using field class 1336 // Using field class
1338 RawField* FlowGraphOptimizer::GetField(intptr_t class_id, 1337 RawField* AotOptimizer::GetField(intptr_t class_id,
1339 const String& field_name) { 1338 const String& field_name) {
1340 Class& cls = Class::Handle(Z, isolate()->class_table()->At(class_id)); 1339 Class& cls = Class::Handle(Z, isolate()->class_table()->At(class_id));
1341 Field& field = Field::Handle(Z); 1340 Field& field = Field::Handle(Z);
1342 while (!cls.IsNull()) { 1341 while (!cls.IsNull()) {
1343 field = cls.LookupInstanceField(field_name); 1342 field = cls.LookupInstanceField(field_name);
1344 if (!field.IsNull()) { 1343 if (!field.IsNull()) {
1345 return field.raw(); 1344 return field.raw();
1346 } 1345 }
1347 cls = cls.SuperClass(); 1346 cls = cls.SuperClass();
1348 } 1347 }
1349 return Field::null(); 1348 return Field::null();
1350 } 1349 }
1351 1350
1352 1351
1353 // Use CHA to determine if the call needs a class check: if the callee's 1352 // 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 1353 // receiver is the same as the caller's receiver and there are no overriden
1355 // callee functions, then no class check is needed. 1354 // callee functions, then no class check is needed.
1356 bool FlowGraphOptimizer::InstanceCallNeedsClassCheck( 1355 bool AotOptimizer::InstanceCallNeedsClassCheck(
1357 InstanceCallInstr* call, RawFunction::Kind kind) const { 1356 InstanceCallInstr* call, RawFunction::Kind kind) const {
1358 if (!FLAG_use_cha_deopt && !isolate()->all_classes_finalized()) { 1357 if (!FLAG_use_cha_deopt && !isolate()->all_classes_finalized()) {
1359 // Even if class or function are private, lazy class finalization 1358 // Even if class or function are private, lazy class finalization
1360 // may later add overriding methods. 1359 // may later add overriding methods.
1361 return true; 1360 return true;
1362 } 1361 }
1363 Definition* callee_receiver = call->ArgumentAt(0); 1362 Definition* callee_receiver = call->ArgumentAt(0);
1364 ASSERT(callee_receiver != NULL); 1363 ASSERT(callee_receiver != NULL);
1365 const Function& function = flow_graph_->function(); 1364 const Function& function = flow_graph_->function();
1366 if (function.IsDynamicFunction() && 1365 if (function.IsDynamicFunction() &&
(...skipping 10 matching lines...) Expand all
1377 name.ToCString(), cls.ToCString()); 1376 name.ToCString(), cls.ToCString());
1378 } 1377 }
1379 thread()->cha()->AddToLeafClasses(cls); 1378 thread()->cha()->AddToLeafClasses(cls);
1380 return false; 1379 return false;
1381 } 1380 }
1382 } 1381 }
1383 return true; 1382 return true;
1384 } 1383 }
1385 1384
1386 1385
1387 bool FlowGraphOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call, 1386 bool AotOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call,
1388 bool allow_check) { 1387 bool allow_check) {
1389 ASSERT(call->HasICData()); 1388 ASSERT(call->HasICData());
1390 const ICData& ic_data = *call->ic_data(); 1389 const ICData& ic_data = *call->ic_data();
1391 ASSERT(ic_data.HasOneTarget()); 1390 ASSERT(ic_data.HasOneTarget());
1392 GrowableArray<intptr_t> class_ids; 1391 GrowableArray<intptr_t> class_ids;
1393 ic_data.GetClassIdsAt(0, &class_ids); 1392 ic_data.GetClassIdsAt(0, &class_ids);
1394 ASSERT(class_ids.length() == 1); 1393 ASSERT(class_ids.length() == 1);
1395 // Inline implicit instance getter. 1394 // Inline implicit instance getter.
1396 const String& field_name = 1395 const String& field_name =
1397 String::Handle(Z, Field::NameFromGetter(call->function_name())); 1396 String::Handle(Z, Field::NameFromGetter(call->function_name()));
(...skipping 30 matching lines...) Expand all
1428 for (Value::Iterator it(load->input_use_list()); 1427 for (Value::Iterator it(load->input_use_list());
1429 !it.Done(); 1428 !it.Done();
1430 it.Advance()) { 1429 it.Advance()) {
1431 it.Current()->SetReachingType(NULL); 1430 it.Current()->SetReachingType(NULL);
1432 } 1431 }
1433 } 1432 }
1434 return true; 1433 return true;
1435 } 1434 }
1436 1435
1437 1436
1438 bool FlowGraphOptimizer::InlineFloat32x4Getter(InstanceCallInstr* call, 1437 bool AotOptimizer::InlineFloat32x4Getter(InstanceCallInstr* call,
1439 MethodRecognizer::Kind getter) { 1438 MethodRecognizer::Kind getter) {
1440 if (!ShouldInlineSimd()) { 1439 if (!ShouldInlineSimd()) {
1441 return false; 1440 return false;
1442 } 1441 }
1443 AddCheckClass(call->ArgumentAt(0), 1442 AddCheckClass(call->ArgumentAt(0),
1444 ICData::ZoneHandle( 1443 ICData::ZoneHandle(
1445 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), 1444 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
1446 call->deopt_id(), 1445 call->deopt_id(),
1447 call->env(), 1446 call->env(),
1448 call); 1447 call);
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
1503 mask, 1502 mask,
1504 call->deopt_id()); 1503 call->deopt_id());
1505 ReplaceCall(call, instr); 1504 ReplaceCall(call, instr);
1506 return true; 1505 return true;
1507 } 1506 }
1508 UNREACHABLE(); 1507 UNREACHABLE();
1509 return false; 1508 return false;
1510 } 1509 }
1511 1510
1512 1511
1513 bool FlowGraphOptimizer::InlineFloat64x2Getter(InstanceCallInstr* call, 1512 bool AotOptimizer::InlineFloat64x2Getter(InstanceCallInstr* call,
1514 MethodRecognizer::Kind getter) { 1513 MethodRecognizer::Kind getter) {
1515 if (!ShouldInlineSimd()) { 1514 if (!ShouldInlineSimd()) {
1516 return false; 1515 return false;
1517 } 1516 }
1518 AddCheckClass(call->ArgumentAt(0), 1517 AddCheckClass(call->ArgumentAt(0),
1519 ICData::ZoneHandle( 1518 ICData::ZoneHandle(
1520 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), 1519 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
1521 call->deopt_id(), 1520 call->deopt_id(),
1522 call->env(), 1521 call->env(),
1523 call); 1522 call);
1524 if ((getter == MethodRecognizer::kFloat64x2GetX) || 1523 if ((getter == MethodRecognizer::kFloat64x2GetX) ||
1525 (getter == MethodRecognizer::kFloat64x2GetY)) { 1524 (getter == MethodRecognizer::kFloat64x2GetY)) {
1526 Simd64x2ShuffleInstr* instr = new(Z) Simd64x2ShuffleInstr( 1525 Simd64x2ShuffleInstr* instr = new(Z) Simd64x2ShuffleInstr(
1527 getter, 1526 getter,
1528 new(Z) Value(call->ArgumentAt(0)), 1527 new(Z) Value(call->ArgumentAt(0)),
1529 0, 1528 0,
1530 call->deopt_id()); 1529 call->deopt_id());
1531 ReplaceCall(call, instr); 1530 ReplaceCall(call, instr);
1532 return true; 1531 return true;
1533 } 1532 }
1534 UNREACHABLE(); 1533 UNREACHABLE();
1535 return false; 1534 return false;
1536 } 1535 }
1537 1536
1538 1537
1539 bool FlowGraphOptimizer::InlineInt32x4Getter(InstanceCallInstr* call, 1538 bool AotOptimizer::InlineInt32x4Getter(InstanceCallInstr* call,
1540 MethodRecognizer::Kind getter) { 1539 MethodRecognizer::Kind getter) {
1541 if (!ShouldInlineSimd()) { 1540 if (!ShouldInlineSimd()) {
1542 return false; 1541 return false;
1543 } 1542 }
1544 AddCheckClass(call->ArgumentAt(0), 1543 AddCheckClass(call->ArgumentAt(0),
1545 ICData::ZoneHandle( 1544 ICData::ZoneHandle(
1546 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), 1545 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
1547 call->deopt_id(), 1546 call->deopt_id(),
1548 call->env(), 1547 call->env(),
1549 call); 1548 call);
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
1604 Int32x4GetFlagInstr* instr = new(Z) Int32x4GetFlagInstr( 1603 Int32x4GetFlagInstr* instr = new(Z) Int32x4GetFlagInstr(
1605 getter, 1604 getter,
1606 new(Z) Value(call->ArgumentAt(0)), 1605 new(Z) Value(call->ArgumentAt(0)),
1607 call->deopt_id()); 1606 call->deopt_id());
1608 ReplaceCall(call, instr); 1607 ReplaceCall(call, instr);
1609 return true; 1608 return true;
1610 } 1609 }
1611 } 1610 }
1612 1611
1613 1612
1614 bool FlowGraphOptimizer::InlineFloat32x4BinaryOp(InstanceCallInstr* call, 1613 bool AotOptimizer::InlineFloat32x4BinaryOp(InstanceCallInstr* call,
1615 Token::Kind op_kind) { 1614 Token::Kind op_kind) {
1616 if (!ShouldInlineSimd()) { 1615 if (!ShouldInlineSimd()) {
1617 return false; 1616 return false;
1618 } 1617 }
1619 ASSERT(call->ArgumentCount() == 2); 1618 ASSERT(call->ArgumentCount() == 2);
1620 Definition* left = call->ArgumentAt(0); 1619 Definition* left = call->ArgumentAt(0);
1621 Definition* right = call->ArgumentAt(1); 1620 Definition* right = call->ArgumentAt(1);
1622 // Type check left. 1621 // Type check left.
1623 AddCheckClass(left, 1622 AddCheckClass(left,
1624 ICData::ZoneHandle( 1623 ICData::ZoneHandle(
(...skipping 12 matching lines...) Expand all
1637 BinaryFloat32x4OpInstr* float32x4_bin_op = 1636 BinaryFloat32x4OpInstr* float32x4_bin_op =
1638 new(Z) BinaryFloat32x4OpInstr( 1637 new(Z) BinaryFloat32x4OpInstr(
1639 op_kind, new(Z) Value(left), new(Z) Value(right), 1638 op_kind, new(Z) Value(left), new(Z) Value(right),
1640 call->deopt_id()); 1639 call->deopt_id());
1641 ReplaceCall(call, float32x4_bin_op); 1640 ReplaceCall(call, float32x4_bin_op);
1642 1641
1643 return true; 1642 return true;
1644 } 1643 }
1645 1644
1646 1645
1647 bool FlowGraphOptimizer::InlineInt32x4BinaryOp(InstanceCallInstr* call, 1646 bool AotOptimizer::InlineInt32x4BinaryOp(InstanceCallInstr* call,
1648 Token::Kind op_kind) { 1647 Token::Kind op_kind) {
1649 if (!ShouldInlineSimd()) { 1648 if (!ShouldInlineSimd()) {
1650 return false; 1649 return false;
1651 } 1650 }
1652 ASSERT(call->ArgumentCount() == 2); 1651 ASSERT(call->ArgumentCount() == 2);
1653 Definition* left = call->ArgumentAt(0); 1652 Definition* left = call->ArgumentAt(0);
1654 Definition* right = call->ArgumentAt(1); 1653 Definition* right = call->ArgumentAt(1);
1655 // Type check left. 1654 // Type check left.
1656 AddCheckClass(left, 1655 AddCheckClass(left,
1657 ICData::ZoneHandle( 1656 ICData::ZoneHandle(
(...skipping 11 matching lines...) Expand all
1669 // Replace call. 1668 // Replace call.
1670 BinaryInt32x4OpInstr* int32x4_bin_op = 1669 BinaryInt32x4OpInstr* int32x4_bin_op =
1671 new(Z) BinaryInt32x4OpInstr( 1670 new(Z) BinaryInt32x4OpInstr(
1672 op_kind, new(Z) Value(left), new(Z) Value(right), 1671 op_kind, new(Z) Value(left), new(Z) Value(right),
1673 call->deopt_id()); 1672 call->deopt_id());
1674 ReplaceCall(call, int32x4_bin_op); 1673 ReplaceCall(call, int32x4_bin_op);
1675 return true; 1674 return true;
1676 } 1675 }
1677 1676
1678 1677
1679 bool FlowGraphOptimizer::InlineFloat64x2BinaryOp(InstanceCallInstr* call, 1678 bool AotOptimizer::InlineFloat64x2BinaryOp(InstanceCallInstr* call,
1680 Token::Kind op_kind) { 1679 Token::Kind op_kind) {
1681 if (!ShouldInlineSimd()) { 1680 if (!ShouldInlineSimd()) {
1682 return false; 1681 return false;
1683 } 1682 }
1684 ASSERT(call->ArgumentCount() == 2); 1683 ASSERT(call->ArgumentCount() == 2);
1685 Definition* left = call->ArgumentAt(0); 1684 Definition* left = call->ArgumentAt(0);
1686 Definition* right = call->ArgumentAt(1); 1685 Definition* right = call->ArgumentAt(1);
1687 // Type check left. 1686 // Type check left.
1688 AddCheckClass(left, 1687 AddCheckClass(left,
1689 ICData::ZoneHandle( 1688 ICData::ZoneHandle(
(...skipping 13 matching lines...) Expand all
1703 new(Z) BinaryFloat64x2OpInstr( 1702 new(Z) BinaryFloat64x2OpInstr(
1704 op_kind, new(Z) Value(left), new(Z) Value(right), 1703 op_kind, new(Z) Value(left), new(Z) Value(right),
1705 call->deopt_id()); 1704 call->deopt_id());
1706 ReplaceCall(call, float64x2_bin_op); 1705 ReplaceCall(call, float64x2_bin_op);
1707 return true; 1706 return true;
1708 } 1707 }
1709 1708
1710 1709
1711 // Only unique implicit instance getters can be currently handled. 1710 // Only unique implicit instance getters can be currently handled.
1712 // Returns false if 'allow_check' is false and a check is needed. 1711 // Returns false if 'allow_check' is false and a check is needed.
1713 bool FlowGraphOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call, 1712 bool AotOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call,
1714 bool allow_check) { 1713 bool allow_check) {
1715 ASSERT(call->HasICData()); 1714 ASSERT(call->HasICData());
1716 const ICData& ic_data = *call->ic_data(); 1715 const ICData& ic_data = *call->ic_data();
1717 if (ic_data.NumberOfUsedChecks() == 0) { 1716 if (ic_data.NumberOfUsedChecks() == 0) {
1718 // No type feedback collected. 1717 // No type feedback collected.
1719 return false; 1718 return false;
1720 } 1719 }
1721 1720
1722 if (!ic_data.HasOneTarget()) { 1721 if (!ic_data.HasOneTarget()) {
1723 // Polymorphic sites are inlined like normal methods by conventional 1722 // Polymorphic sites are inlined like normal methods by conventional
1724 // inlining in FlowGraphInliner. 1723 // inlining in FlowGraphInliner.
1725 return false; 1724 return false;
1726 } 1725 }
1727 1726
1728 const Function& target = Function::Handle(Z, ic_data.GetTargetAt(0)); 1727 const Function& target = Function::Handle(Z, ic_data.GetTargetAt(0));
1729 if (target.kind() != RawFunction::kImplicitGetter) { 1728 if (target.kind() != RawFunction::kImplicitGetter) {
1730 // Non-implicit getters are inlined like normal methods by conventional 1729 // Non-implicit getters are inlined like normal methods by conventional
1731 // inlining in FlowGraphInliner. 1730 // inlining in FlowGraphInliner.
1732 return false; 1731 return false;
1733 } 1732 }
1734 return InlineImplicitInstanceGetter(call, allow_check); 1733 return InlineImplicitInstanceGetter(call, allow_check);
1735 } 1734 }
1736 1735
1737 1736
1738 bool FlowGraphOptimizer::TryReplaceInstanceCallWithInline( 1737 bool AotOptimizer::TryReplaceInstanceCallWithInline(
1739 InstanceCallInstr* call) { 1738 InstanceCallInstr* call) {
1740 Function& target = Function::Handle(Z); 1739 Function& target = Function::Handle(Z);
1741 GrowableArray<intptr_t> class_ids; 1740 GrowableArray<intptr_t> class_ids;
1742 call->ic_data()->GetCheckAt(0, &class_ids, &target); 1741 call->ic_data()->GetCheckAt(0, &class_ids, &target);
1743 const intptr_t receiver_cid = class_ids[0]; 1742 const intptr_t receiver_cid = class_ids[0];
1744 1743
1745 TargetEntryInstr* entry; 1744 TargetEntryInstr* entry;
1746 Definition* last; 1745 Definition* last;
1747 if (!FlowGraphInliner::TryInlineRecognizedMethod(flow_graph_, 1746 if (!FlowGraphInliner::TryInlineRecognizedMethod(flow_graph_,
1748 receiver_cid, 1747 receiver_cid,
(...skipping 23 matching lines...) Expand all
1772 last->LinkTo(call); 1771 last->LinkTo(call);
1773 // Remove through the iterator. 1772 // Remove through the iterator.
1774 ASSERT(current_iterator()->Current() == call); 1773 ASSERT(current_iterator()->Current() == call);
1775 current_iterator()->RemoveCurrentFromGraph(); 1774 current_iterator()->RemoveCurrentFromGraph();
1776 call->set_previous(NULL); 1775 call->set_previous(NULL);
1777 call->set_next(NULL); 1776 call->set_next(NULL);
1778 return true; 1777 return true;
1779 } 1778 }
1780 1779
1781 1780
1782 void FlowGraphOptimizer::ReplaceWithMathCFunction( 1781 void AotOptimizer::ReplaceWithMathCFunction(
1783 InstanceCallInstr* call, 1782 InstanceCallInstr* call,
1784 MethodRecognizer::Kind recognized_kind) { 1783 MethodRecognizer::Kind recognized_kind) {
1785 AddReceiverCheck(call); 1784 AddReceiverCheck(call);
1786 ZoneGrowableArray<Value*>* args = 1785 ZoneGrowableArray<Value*>* args =
1787 new(Z) ZoneGrowableArray<Value*>(call->ArgumentCount()); 1786 new(Z) ZoneGrowableArray<Value*>(call->ArgumentCount());
1788 for (intptr_t i = 0; i < call->ArgumentCount(); i++) { 1787 for (intptr_t i = 0; i < call->ArgumentCount(); i++) {
1789 args->Add(new(Z) Value(call->ArgumentAt(i))); 1788 args->Add(new(Z) Value(call->ArgumentAt(i)));
1790 } 1789 }
1791 InvokeMathCFunctionInstr* invoke = 1790 InvokeMathCFunctionInstr* invoke =
1792 new(Z) InvokeMathCFunctionInstr(args, 1791 new(Z) InvokeMathCFunctionInstr(args,
(...skipping 20 matching lines...) Expand all
1813 case kTypedDataFloat32x4ArrayCid: 1812 case kTypedDataFloat32x4ArrayCid:
1814 case kTypedDataInt32x4ArrayCid: 1813 case kTypedDataInt32x4ArrayCid:
1815 return true; 1814 return true;
1816 default: 1815 default:
1817 return false; 1816 return false;
1818 } 1817 }
1819 } 1818 }
1820 1819
1821 1820
1822 // Inline only simple, frequently called core library methods. 1821 // Inline only simple, frequently called core library methods.
1823 bool FlowGraphOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) { 1822 bool AotOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) {
1824 ASSERT(call->HasICData()); 1823 ASSERT(call->HasICData());
1825 const ICData& ic_data = *call->ic_data(); 1824 const ICData& ic_data = *call->ic_data();
1826 if ((ic_data.NumberOfUsedChecks() == 0) || !ic_data.HasOneTarget()) { 1825 if ((ic_data.NumberOfUsedChecks() == 0) || !ic_data.HasOneTarget()) {
1827 // No type feedback collected or multiple targets found. 1826 // No type feedback collected or multiple targets found.
1828 return false; 1827 return false;
1829 } 1828 }
1830 1829
1831 Function& target = Function::Handle(Z); 1830 Function& target = Function::Handle(Z);
1832 GrowableArray<intptr_t> class_ids; 1831 GrowableArray<intptr_t> class_ids;
1833 ic_data.GetCheckAt(0, &class_ids, &target); 1832 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), 2045 new(Z) Value(int32_mask),
2047 call->deopt_id()); 2046 call->deopt_id());
2048 ReplaceCall(call, bit_and); 2047 ReplaceCall(call, bit_and);
2049 return true; 2048 return true;
2050 } 2049 }
2051 } 2050 }
2052 return false; 2051 return false;
2053 } 2052 }
2054 2053
2055 2054
2056 bool FlowGraphOptimizer::TryInlineFloat32x4Constructor( 2055 bool AotOptimizer::TryInlineFloat32x4Constructor(
2057 StaticCallInstr* call, 2056 StaticCallInstr* call,
2058 MethodRecognizer::Kind recognized_kind) { 2057 MethodRecognizer::Kind recognized_kind) {
2059 if (FLAG_precompilation) { 2058 ASSERT(FLAG_precompilation);
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; 2059 return false;
2100 } 2060 }
2101 2061
2102 2062
2103 bool FlowGraphOptimizer::TryInlineFloat64x2Constructor( 2063 bool AotOptimizer::TryInlineFloat64x2Constructor(
2104 StaticCallInstr* call, 2064 StaticCallInstr* call,
2105 MethodRecognizer::Kind recognized_kind) { 2065 MethodRecognizer::Kind recognized_kind) {
2106 if (FLAG_precompilation) { 2066 ASSERT(FLAG_precompilation);
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; 2067 return false;
2139 } 2068 }
2140 2069
2141 2070
2142 bool FlowGraphOptimizer::TryInlineInt32x4Constructor( 2071 bool AotOptimizer::TryInlineInt32x4Constructor(
2143 StaticCallInstr* call, 2072 StaticCallInstr* call,
2144 MethodRecognizer::Kind recognized_kind) { 2073 MethodRecognizer::Kind recognized_kind) {
2145 if (FLAG_precompilation) { 2074 ASSERT(FLAG_precompilation);
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; 2075 return false;
2180 } 2076 }
2181 2077
2182 2078
2183 bool FlowGraphOptimizer::TryInlineFloat32x4Method( 2079 bool AotOptimizer::TryInlineFloat32x4Method(
2184 InstanceCallInstr* call, 2080 InstanceCallInstr* call,
2185 MethodRecognizer::Kind recognized_kind) { 2081 MethodRecognizer::Kind recognized_kind) {
2186 if (!ShouldInlineSimd()) { 2082 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 } 2083 }
2345 2084
2346 2085
2347 bool FlowGraphOptimizer::TryInlineFloat64x2Method( 2086 bool AotOptimizer::TryInlineFloat64x2Method(
2348 InstanceCallInstr* call, 2087 InstanceCallInstr* call,
2349 MethodRecognizer::Kind recognized_kind) { 2088 MethodRecognizer::Kind recognized_kind) {
2350 if (!ShouldInlineSimd()) { 2089 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 } 2090 }
2404 2091
2405 2092
2406 bool FlowGraphOptimizer::TryInlineInt32x4Method( 2093 bool AotOptimizer::TryInlineInt32x4Method(
2407 InstanceCallInstr* call, 2094 InstanceCallInstr* call,
2408 MethodRecognizer::Kind recognized_kind) { 2095 MethodRecognizer::Kind recognized_kind) {
2409 if (!ShouldInlineSimd()) { 2096 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 } 2097 }
2469 2098
2470 2099
2471 // If type tests specified by 'ic_data' do not depend on type arguments, 2100 // 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). 2101 // 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. 2102 // If all tests yield the same result, return it otherwise return Bool::null.
2474 // If no mapping is possible, 'results' is empty. 2103 // If no mapping is possible, 'results' is empty.
2475 // An instance-of test returning all same results can be converted to a class 2104 // An instance-of test returning all same results can be converted to a class
2476 // check. 2105 // check.
2477 RawBool* FlowGraphOptimizer::InstanceOfAsBool( 2106 RawBool* AotOptimizer::InstanceOfAsBool(
2478 const ICData& ic_data, 2107 const ICData& ic_data,
2479 const AbstractType& type, 2108 const AbstractType& type,
2480 ZoneGrowableArray<intptr_t>* results) const { 2109 ZoneGrowableArray<intptr_t>* results) const {
2481 ASSERT(results->is_empty()); 2110 ASSERT(results->is_empty());
2482 ASSERT(ic_data.NumArgsTested() == 1); // Unary checks only. 2111 ASSERT(ic_data.NumArgsTested() == 1); // Unary checks only.
2483 if (type.IsFunctionType() || type.IsDartFunctionType() || 2112 if (type.IsFunctionType() || type.IsDartFunctionType() ||
2484 !type.IsInstantiated() || type.IsMalformedOrMalbounded()) { 2113 !type.IsInstantiated() || type.IsMalformedOrMalbounded()) {
2485 return Bool::null(); 2114 return Bool::null();
2486 } 2115 }
2487 const Class& type_class = Class::Handle(Z, type.type_class()); 2116 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()) { 2155 if (is_subtype != prev.value()) {
2527 results_differ = true; 2156 results_differ = true;
2528 } 2157 }
2529 } 2158 }
2530 } 2159 }
2531 return results_differ ? Bool::null() : prev.raw(); 2160 return results_differ ? Bool::null() : prev.raw();
2532 } 2161 }
2533 2162
2534 2163
2535 // Returns true if checking against this type is a direct class id comparison. 2164 // Returns true if checking against this type is a direct class id comparison.
2536 bool FlowGraphOptimizer::TypeCheckAsClassEquality(const AbstractType& type) { 2165 bool AotOptimizer::TypeCheckAsClassEquality(const AbstractType& type) {
2537 ASSERT(type.IsFinalized() && !type.IsMalformedOrMalbounded()); 2166 ASSERT(type.IsFinalized() && !type.IsMalformedOrMalbounded());
2538 // Requires CHA. 2167 // Requires CHA.
2539 if (!type.IsInstantiated()) return false; 2168 if (!type.IsInstantiated()) return false;
2540 // Function types have different type checking rules. 2169 // Function types have different type checking rules.
2541 if (type.IsFunctionType()) return false; 2170 if (type.IsFunctionType()) return false;
2542 const Class& type_class = Class::Handle(type.type_class()); 2171 const Class& type_class = Class::Handle(type.type_class());
2543 // Could be an interface check? 2172 // Could be an interface check?
2544 if (CHA::IsImplemented(type_class)) return false; 2173 if (CHA::IsImplemented(type_class)) return false;
2545 // Check if there are subclasses. 2174 // Check if there are subclasses.
2546 if (CHA::HasSubclasses(type_class)) { 2175 if (CHA::HasSubclasses(type_class)) {
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
2630 TryAddTest(results, kBigintCid, true); 2259 TryAddTest(results, kBigintCid, true);
2631 // Cannot deoptimize since all tests returning true have been added. 2260 // Cannot deoptimize since all tests returning true have been added.
2632 return false; 2261 return false;
2633 } 2262 }
2634 2263
2635 return true; // May deoptimize since we have not identified all 'true' tests. 2264 return true; // May deoptimize since we have not identified all 'true' tests.
2636 } 2265 }
2637 2266
2638 2267
2639 // TODO(srdjan): Use ICData to check if always true or false. 2268 // TODO(srdjan): Use ICData to check if always true or false.
2640 void FlowGraphOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) { 2269 void AotOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) {
2641 ASSERT(Token::IsTypeTestOperator(call->token_kind())); 2270 ASSERT(Token::IsTypeTestOperator(call->token_kind()));
2642 Definition* left = call->ArgumentAt(0); 2271 Definition* left = call->ArgumentAt(0);
2643 Definition* type_args = NULL; 2272 Definition* type_args = NULL;
2644 AbstractType& type = AbstractType::ZoneHandle(Z); 2273 AbstractType& type = AbstractType::ZoneHandle(Z);
2645 bool negate = false; 2274 bool negate = false;
2646 if (call->ArgumentCount() == 2) { 2275 if (call->ArgumentCount() == 2) {
2647 type_args = flow_graph()->constant_null(); 2276 type_args = flow_graph()->constant_null();
2648 if (call->function_name().raw() == 2277 if (call->function_name().raw() ==
2649 Library::PrivateCoreLibName(Symbols::_instanceOfNum()).raw()) { 2278 Library::PrivateCoreLibName(Symbols::_instanceOfNum()).raw()) {
2650 type = Type::Number(); 2279 type = Type::Number();
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
2738 new(Z) Value(left), 2367 new(Z) Value(left),
2739 new(Z) Value(type_args), 2368 new(Z) Value(type_args),
2740 type, 2369 type,
2741 negate, 2370 negate,
2742 call->deopt_id()); 2371 call->deopt_id());
2743 ReplaceCall(call, instance_of); 2372 ReplaceCall(call, instance_of);
2744 } 2373 }
2745 2374
2746 2375
2747 // TODO(srdjan): Apply optimizations as in ReplaceWithInstanceOf (TestCids). 2376 // TODO(srdjan): Apply optimizations as in ReplaceWithInstanceOf (TestCids).
2748 void FlowGraphOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) { 2377 void AotOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) {
2749 ASSERT(Token::IsTypeCastOperator(call->token_kind())); 2378 ASSERT(Token::IsTypeCastOperator(call->token_kind()));
2750 Definition* left = call->ArgumentAt(0); 2379 Definition* left = call->ArgumentAt(0);
2751 Definition* type_args = call->ArgumentAt(1); 2380 Definition* type_args = call->ArgumentAt(1);
2752 const AbstractType& type = 2381 const AbstractType& type =
2753 AbstractType::Cast(call->ArgumentAt(2)->AsConstant()->value()); 2382 AbstractType::Cast(call->ArgumentAt(2)->AsConstant()->value());
2754 ASSERT(!type.IsMalformedOrMalbounded()); 2383 ASSERT(!type.IsMalformedOrMalbounded());
2755 const ICData& unary_checks = 2384 const ICData& unary_checks =
2756 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks()); 2385 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks());
2757 if ((unary_checks.NumberOfChecks() > 0) && 2386 if ((unary_checks.NumberOfChecks() > 0) &&
2758 (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks)) { 2387 (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks)) {
(...skipping 22 matching lines...) Expand all
2781 new(Z) AssertAssignableInstr(call->token_pos(), 2410 new(Z) AssertAssignableInstr(call->token_pos(),
2782 new(Z) Value(left), 2411 new(Z) Value(left),
2783 new(Z) Value(type_args), 2412 new(Z) Value(type_args),
2784 type, 2413 type,
2785 dst_name, 2414 dst_name,
2786 call->deopt_id()); 2415 call->deopt_id());
2787 ReplaceCall(call, assert_as); 2416 ReplaceCall(call, assert_as);
2788 } 2417 }
2789 2418
2790 2419
2791 bool FlowGraphOptimizer::IsBlackListedForInlining(intptr_t call_deopt_id) { 2420 bool AotOptimizer::IsBlackListedForInlining(intptr_t call_deopt_id) {
2792 for (intptr_t i = 0; i < inlining_black_list_->length(); ++i) { 2421 for (intptr_t i = 0; i < inlining_black_list_->length(); ++i) {
2793 if ((*inlining_black_list_)[i] == call_deopt_id) return true; 2422 if ((*inlining_black_list_)[i] == call_deopt_id) return true;
2794 } 2423 }
2795 return false; 2424 return false;
2796 } 2425 }
2797 2426
2798 // Special optimizations when running in --noopt mode. 2427 // Special optimizations when running in --noopt mode.
2799 void FlowGraphOptimizer::InstanceCallNoopt(InstanceCallInstr* instr) { 2428 void AotOptimizer::InstanceCallNoopt(InstanceCallInstr* instr) {
2800 // TODO(srdjan): Investigate other attempts, as they are not allowed to 2429 // TODO(srdjan): Investigate other attempts, as they are not allowed to
2801 // deoptimize. 2430 // deoptimize.
2802 2431
2803 // Type test is special as it always gets converted into inlined code. 2432 // Type test is special as it always gets converted into inlined code.
2804 const Token::Kind op_kind = instr->token_kind(); 2433 const Token::Kind op_kind = instr->token_kind();
2805 if (Token::IsTypeTestOperator(op_kind)) { 2434 if (Token::IsTypeTestOperator(op_kind)) {
2806 ReplaceWithInstanceOf(instr); 2435 ReplaceWithInstanceOf(instr);
2807 return; 2436 return;
2808 } 2437 }
2809 if (Token::IsTypeCastOperator(op_kind)) { 2438 if (Token::IsTypeCastOperator(op_kind)) {
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
2928 new(Z) PolymorphicInstanceCallInstr(instr, ic_data, 2557 new(Z) PolymorphicInstanceCallInstr(instr, ic_data,
2929 /* with_checks = */ false); 2558 /* with_checks = */ false);
2930 instr->ReplaceWith(call, current_iterator()); 2559 instr->ReplaceWith(call, current_iterator());
2931 return; 2560 return;
2932 } 2561 }
2933 } 2562 }
2934 2563
2935 2564
2936 // Tries to optimize instance call by replacing it with a faster instruction 2565 // Tries to optimize instance call by replacing it with a faster instruction
2937 // (e.g, binary op, field load, ..). 2566 // (e.g, binary op, field load, ..).
2938 void FlowGraphOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { 2567 void AotOptimizer::VisitInstanceCall(InstanceCallInstr* instr) {
2939 if (FLAG_precompilation) { 2568 ASSERT(FLAG_precompilation);
2940 InstanceCallNoopt(instr); 2569 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 } 2570 }
3047 2571
3048 2572
3049 void FlowGraphOptimizer::VisitStaticCall(StaticCallInstr* call) { 2573 void AotOptimizer::VisitStaticCall(StaticCallInstr* call) {
3050 if (!CanUnboxDouble()) { 2574 if (!CanUnboxDouble()) {
3051 return; 2575 return;
3052 } 2576 }
3053 MethodRecognizer::Kind recognized_kind = 2577 MethodRecognizer::Kind recognized_kind =
3054 MethodRecognizer::RecognizeKind(call->function()); 2578 MethodRecognizer::RecognizeKind(call->function());
3055 MathUnaryInstr::MathUnaryKind unary_kind; 2579 MathUnaryInstr::MathUnaryKind unary_kind;
3056 switch (recognized_kind) { 2580 switch (recognized_kind) {
3057 case MethodRecognizer::kMathSqrt: 2581 case MethodRecognizer::kMathSqrt:
3058 unary_kind = MathUnaryInstr::kSqrt; 2582 unary_kind = MathUnaryInstr::kSqrt;
3059 break; 2583 break;
3060 case MethodRecognizer::kMathSin: 2584 case MethodRecognizer::kMathSin:
3061 unary_kind = MathUnaryInstr::kSin; 2585 unary_kind = MathUnaryInstr::kSin;
3062 break; 2586 break;
3063 case MethodRecognizer::kMathCos: 2587 case MethodRecognizer::kMathCos:
3064 unary_kind = MathUnaryInstr::kCos; 2588 unary_kind = MathUnaryInstr::kCos;
3065 break; 2589 break;
3066 default: 2590 default:
3067 unary_kind = MathUnaryInstr::kIllegal; 2591 unary_kind = MathUnaryInstr::kIllegal;
3068 break; 2592 break;
3069 } 2593 }
3070 if (unary_kind != MathUnaryInstr::kIllegal) { 2594 if (unary_kind != MathUnaryInstr::kIllegal) {
3071 if (FLAG_precompilation) { 2595 ASSERT(FLAG_precompilation);
3072 // TODO(srdjan): Adapt MathUnaryInstr to allow tagged inputs as well. 2596 // 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; 2597 return;
3081 } 2598 }
2599
3082 switch (recognized_kind) { 2600 switch (recognized_kind) {
3083 case MethodRecognizer::kFloat32x4Zero: 2601 case MethodRecognizer::kFloat32x4Zero:
3084 case MethodRecognizer::kFloat32x4Splat: 2602 case MethodRecognizer::kFloat32x4Splat:
3085 case MethodRecognizer::kFloat32x4Constructor: 2603 case MethodRecognizer::kFloat32x4Constructor:
3086 case MethodRecognizer::kFloat32x4FromFloat64x2: 2604 case MethodRecognizer::kFloat32x4FromFloat64x2:
3087 TryInlineFloat32x4Constructor(call, recognized_kind); 2605 TryInlineFloat32x4Constructor(call, recognized_kind);
3088 break; 2606 break;
3089 case MethodRecognizer::kFloat64x2Constructor: 2607 case MethodRecognizer::kFloat64x2Constructor:
3090 case MethodRecognizer::kFloat64x2Zero: 2608 case MethodRecognizer::kFloat64x2Zero:
3091 case MethodRecognizer::kFloat64x2Splat: 2609 case MethodRecognizer::kFloat64x2Splat:
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
3147 } 2665 }
3148 } 2666 }
3149 break; 2667 break;
3150 } 2668 }
3151 case MethodRecognizer::kMathDoublePow: 2669 case MethodRecognizer::kMathDoublePow:
3152 case MethodRecognizer::kMathTan: 2670 case MethodRecognizer::kMathTan:
3153 case MethodRecognizer::kMathAsin: 2671 case MethodRecognizer::kMathAsin:
3154 case MethodRecognizer::kMathAcos: 2672 case MethodRecognizer::kMathAcos:
3155 case MethodRecognizer::kMathAtan: 2673 case MethodRecognizer::kMathAtan:
3156 case MethodRecognizer::kMathAtan2: { 2674 case MethodRecognizer::kMathAtan2: {
3157 if (FLAG_precompilation) { 2675 ASSERT(FLAG_precompilation);
3158 // No UnboxDouble instructons allowed. 2676 // No UnboxDouble instructions allowed.
3159 return; 2677 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 } 2678 }
3176 case MethodRecognizer::kDoubleFromInteger: { 2679 case MethodRecognizer::kDoubleFromInteger: {
3177 if (call->HasICData() && (call->ic_data()->NumberOfChecks() == 1)) { 2680 if (call->HasICData() && (call->ic_data()->NumberOfChecks() == 1)) {
3178 const ICData& ic_data = *call->ic_data(); 2681 const ICData& ic_data = *call->ic_data();
3179 if (CanUnboxDouble()) { 2682 if (CanUnboxDouble()) {
3180 if (ArgIsAlways(kSmiCid, ic_data, 1)) { 2683 if (ArgIsAlways(kSmiCid, ic_data, 1)) {
3181 Definition* arg = call->ArgumentAt(1); 2684 Definition* arg = call->ArgumentAt(1);
3182 AddCheckSmi(arg, call->deopt_id(), call->env(), call); 2685 AddCheckSmi(arg, call->deopt_id(), call->env(), call);
3183 ReplaceCall(call, 2686 ReplaceCall(call,
3184 new(Z) SmiToDoubleInstr(new(Z) Value(arg), 2687 new(Z) SmiToDoubleInstr(new(Z) Value(arg),
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
3220 default: 2723 default:
3221 break; 2724 break;
3222 } 2725 }
3223 } 2726 }
3224 } 2727 }
3225 } 2728 }
3226 } 2729 }
3227 } 2730 }
3228 2731
3229 2732
3230 void FlowGraphOptimizer::VisitStoreInstanceField( 2733 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 2734 // Replace generic allocation with a sequence of inlined allocation and
3286 // explicit initalizing stores. 2735 // explicit initalizing stores.
3287 AllocateUninitializedContextInstr* replacement = 2736 AllocateUninitializedContextInstr* replacement =
3288 new AllocateUninitializedContextInstr(instr->token_pos(), 2737 new AllocateUninitializedContextInstr(instr->token_pos(),
3289 instr->num_context_variables()); 2738 instr->num_context_variables());
3290 instr->ReplaceWith(replacement, current_iterator()); 2739 instr->ReplaceWith(replacement, current_iterator());
3291 2740
3292 StoreInstanceFieldInstr* store = 2741 StoreInstanceFieldInstr* store =
3293 new(Z) StoreInstanceFieldInstr(Context::parent_offset(), 2742 new(Z) StoreInstanceFieldInstr(Context::parent_offset(),
3294 new Value(replacement), 2743 new Value(replacement),
(...skipping 14 matching lines...) Expand all
3309 instr->token_pos()); 2758 instr->token_pos());
3310 // Storing into uninitialized memory; remember to prevent dead store 2759 // Storing into uninitialized memory; remember to prevent dead store
3311 // elimination and ensure proper GC barrier. 2760 // elimination and ensure proper GC barrier.
3312 store->set_is_object_reference_initialization(true); 2761 store->set_is_object_reference_initialization(true);
3313 flow_graph_->InsertAfter(cursor, store, NULL, FlowGraph::kEffect); 2762 flow_graph_->InsertAfter(cursor, store, NULL, FlowGraph::kEffect);
3314 cursor = store; 2763 cursor = store;
3315 } 2764 }
3316 } 2765 }
3317 2766
3318 2767
3319 void FlowGraphOptimizer::VisitLoadCodeUnits(LoadCodeUnitsInstr* instr) { 2768 void AotOptimizer::VisitLoadCodeUnits(LoadCodeUnitsInstr* instr) {
3320 // TODO(zerny): Use kUnboxedUint32 once it is fully supported/optimized. 2769 // TODO(zerny): Use kUnboxedUint32 once it is fully supported/optimized.
3321 #if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_ARM) 2770 #if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_ARM)
3322 if (!instr->can_pack_into_smi()) 2771 if (!instr->can_pack_into_smi())
3323 instr->set_representation(kUnboxedMint); 2772 instr->set_representation(kUnboxedMint);
3324 #endif 2773 #endif
3325 } 2774 }
3326 2775
3327 2776
3328 bool FlowGraphOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr, 2777 bool AotOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr,
3329 const ICData& unary_ic_data, 2778 const ICData& unary_ic_data,
3330 bool allow_checks) { 2779 bool allow_checks) {
3331 ASSERT((unary_ic_data.NumberOfChecks() > 0) && 2780 ASSERT((unary_ic_data.NumberOfChecks() > 0) &&
3332 (unary_ic_data.NumArgsTested() == 1)); 2781 (unary_ic_data.NumArgsTested() == 1));
3333 if (I->flags().type_checks()) { 2782 if (I->flags().type_checks()) {
3334 // Checked mode setters are inlined like normal methods by conventional 2783 // Checked mode setters are inlined like normal methods by conventional
3335 // inlining. 2784 // inlining.
3336 return false; 2785 return false;
3337 } 2786 }
3338 2787
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
3406 2855
3407 // Discard the environment from the original instruction because the store 2856 // Discard the environment from the original instruction because the store
3408 // can't deoptimize. 2857 // can't deoptimize.
3409 instr->RemoveEnvironment(); 2858 instr->RemoveEnvironment();
3410 ReplaceCall(instr, store); 2859 ReplaceCall(instr, store);
3411 return true; 2860 return true;
3412 } 2861 }
3413 2862
3414 2863
3415 } // namespace dart 2864 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698