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

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

Powered by Google App Engine
This is Rietveld 408576698