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

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

Issue 10802025: Fuse compare with branch at graph building time. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 5 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 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/globals.h" // Needed here to get TARGET_ARCH_IA32. 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_IA32.
6 #if defined(TARGET_ARCH_IA32) 6 #if defined(TARGET_ARCH_IA32)
7 7
8 #include "vm/intermediate_language.h" 8 #include "vm/intermediate_language.h"
9 9
10 #include "lib/error.h" 10 #include "lib/error.h"
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after
196 const intptr_t kNumInputs = 2; 196 const intptr_t kNumInputs = 2;
197 if (receiver_class_id() != kObject) { 197 if (receiver_class_id() != kObject) {
198 ASSERT((receiver_class_id() == kSmi) || (receiver_class_id() == kDouble)); 198 ASSERT((receiver_class_id() == kSmi) || (receiver_class_id() == kDouble));
199 const intptr_t kNumTemps = 1; 199 const intptr_t kNumTemps = 1;
200 LocationSummary* locs = new LocationSummary(kNumInputs, 200 LocationSummary* locs = new LocationSummary(kNumInputs,
201 kNumTemps, 201 kNumTemps,
202 LocationSummary::kNoCall); 202 LocationSummary::kNoCall);
203 locs->set_in(0, Location::RequiresRegister()); 203 locs->set_in(0, Location::RequiresRegister());
204 locs->set_in(1, Location::RequiresRegister()); 204 locs->set_in(1, Location::RequiresRegister());
205 locs->set_temp(0, Location::RequiresRegister()); 205 locs->set_temp(0, Location::RequiresRegister());
206 if (!is_fused_with_branch()) { 206 locs->set_out(Location::RequiresRegister());
207 locs->set_out(Location::RequiresRegister());
208 }
209 return locs; 207 return locs;
210 } 208 }
211 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { 209 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) {
212 const intptr_t kNumTemps = 1; 210 const intptr_t kNumTemps = 1;
213 LocationSummary* locs = new LocationSummary(kNumInputs, 211 LocationSummary* locs = new LocationSummary(kNumInputs,
214 kNumTemps, 212 kNumTemps,
215 LocationSummary::kCall); 213 LocationSummary::kCall);
216 locs->set_in(0, Location::RequiresRegister()); 214 locs->set_in(0, Location::RequiresRegister());
217 locs->set_in(1, Location::RequiresRegister()); 215 locs->set_in(1, Location::RequiresRegister());
218 locs->set_temp(0, Location::RequiresRegister()); 216 locs->set_temp(0, Location::RequiresRegister());
219 if (!is_fused_with_branch()) { 217 locs->set_out(Location::RegisterLocation(EAX));
220 locs->set_out(Location::RegisterLocation(EAX));
221 }
222 return locs; 218 return locs;
223 } 219 }
224 const intptr_t kNumTemps = 0; 220 const intptr_t kNumTemps = 0;
225 LocationSummary* locs = new LocationSummary(kNumInputs, 221 LocationSummary* locs = new LocationSummary(kNumInputs,
226 kNumTemps, 222 kNumTemps,
227 LocationSummary::kCall); 223 LocationSummary::kCall);
228 locs->set_in(0, Location::RequiresRegister()); 224 locs->set_in(0, Location::RequiresRegister());
229 locs->set_in(1, Location::RequiresRegister()); 225 locs->set_in(1, Location::RequiresRegister());
230 if (!is_fused_with_branch()) { 226 locs->set_out(Location::RegisterLocation(EAX));
231 locs->set_out(Location::RegisterLocation(EAX));
232 }
233 return locs; 227 return locs;
234 } 228 }
235 229
236 230
237 // Optional integer arguments can often be null. Null is not collected 231 // Optional integer arguments can often be null. Null is not collected
238 // by IC data. TODO(srdjan): Shall we collect null classes in ICData as well? 232 // by IC data. TODO(srdjan): Shall we collect null classes in ICData as well?
239 static void EmitSmiEqualityCompare(FlowGraphCompiler* compiler, 233 static void EmitSmiEqualityCompare(FlowGraphCompiler* compiler,
240 EqualityCompareComp* comp) { 234 EqualityCompareComp* comp) {
241 Register left = comp->locs()->in(0).reg(); 235 Register left = comp->locs()->in(0).reg();
242 Register right = comp->locs()->in(1).reg(); 236 Register right = comp->locs()->in(1).reg();
243 Register temp = comp->locs()->temp(0).reg(); 237 Register temp = comp->locs()->temp(0).reg();
244 Label* deopt = compiler->AddDeoptStub(comp->cid(), 238 Label* deopt = compiler->AddDeoptStub(comp->cid(),
245 comp->token_pos(), 239 comp->token_pos(),
246 comp->try_index(), 240 comp->try_index(),
247 kDeoptSmiCompareSmi, 241 kDeoptSmiCompareSmi,
248 left, 242 left,
249 right); 243 right);
250 __ movl(temp, left); 244 __ movl(temp, left);
251 __ orl(temp, right); 245 __ orl(temp, right);
252 __ testl(temp, Immediate(kSmiTagMask)); 246 __ testl(temp, Immediate(kSmiTagMask));
253 __ j(NOT_ZERO, deopt); 247 __ j(NOT_ZERO, deopt);
254 __ cmpl(left, right); 248 __ cmpl(left, right);
255 if (comp->is_fused_with_branch()) { 249 Register result = comp->locs()->out().reg();
256 comp->fused_with_branch()->EmitBranchOnCondition(compiler, EQUAL); 250 Label load_true, done;
257 } else { 251 __ j(EQUAL, &load_true, Assembler::kNearJump);
258 Register result = comp->locs()->out().reg(); 252 __ LoadObject(result, compiler->bool_false());
259 Label load_true, done; 253 __ jmp(&done, Assembler::kNearJump);
260 __ j(EQUAL, &load_true, Assembler::kNearJump); 254 __ Bind(&load_true);
261 __ LoadObject(result, compiler->bool_false()); 255 __ LoadObject(result, compiler->bool_true());
262 __ jmp(&done, Assembler::kNearJump); 256 __ Bind(&done);
263 __ Bind(&load_true);
264 __ LoadObject(result, compiler->bool_true());
265 __ Bind(&done);
266 }
267 } 257 }
268 258
269 259
270 // TODO(srdjan): Add support for mixed Smi/Double equality 260 // TODO(srdjan): Add support for mixed Smi/Double equality
271 // (see LoadDoubleOrSmiToXmm). 261 // (see LoadDoubleOrSmiToXmm).
272 static void EmitDoubleEqualityCompare(FlowGraphCompiler* compiler, 262 static void EmitDoubleEqualityCompare(FlowGraphCompiler* compiler,
273 EqualityCompareComp* comp) { 263 EqualityCompareComp* comp) {
274 Register left = comp->locs()->in(0).reg(); 264 Register left = comp->locs()->in(0).reg();
275 Register right = comp->locs()->in(1).reg(); 265 Register right = comp->locs()->in(1).reg();
276 Register temp = comp->locs()->temp(0).reg(); 266 Register temp = comp->locs()->temp(0).reg();
277 Label* deopt = compiler->AddDeoptStub(comp->cid(), 267 Label* deopt = compiler->AddDeoptStub(comp->cid(),
278 comp->token_pos(), 268 comp->token_pos(),
279 comp->try_index(), 269 comp->try_index(),
280 kDeoptDoubleCompareDouble, 270 kDeoptDoubleCompareDouble,
281 left, 271 left,
282 right); 272 right);
283 Label done, is_false, is_true; 273 Label done, is_false, is_true;
284 __ CompareClassId(left, kDouble, temp); 274 __ CompareClassId(left, kDouble, temp);
285 __ j(NOT_EQUAL, deopt); 275 __ j(NOT_EQUAL, deopt);
286 __ CompareClassId(right, kDouble, temp); 276 __ CompareClassId(right, kDouble, temp);
287 __ j(NOT_EQUAL, deopt); 277 __ j(NOT_EQUAL, deopt);
288 __ movsd(XMM0, FieldAddress(left, Double::value_offset())); 278 __ movsd(XMM0, FieldAddress(left, Double::value_offset()));
289 __ movsd(XMM1, FieldAddress(right, Double::value_offset())); 279 __ movsd(XMM1, FieldAddress(right, Double::value_offset()));
290 if (comp->is_fused_with_branch()) { 280 compiler->EmitDoubleCompareBool(
291 compiler->EmitDoubleCompareBranch( 281 EQUAL, XMM0, XMM1, comp->locs()->out().reg());
292 EQUAL, XMM0, XMM1, comp->fused_with_branch());
293 } else {
294 compiler->EmitDoubleCompareBool(
295 EQUAL, XMM0, XMM1, comp->locs()->out().reg());
296 }
297 } 282 }
298 283
299 284
300 static void EmitEqualityAsInstanceCall(FlowGraphCompiler* compiler, 285 static void EmitEqualityAsInstanceCall(FlowGraphCompiler* compiler,
301 EqualityCompareComp* comp) { 286 EqualityCompareComp* comp) {
302 compiler->AddCurrentDescriptor(PcDescriptors::kDeopt, 287 compiler->AddCurrentDescriptor(PcDescriptors::kDeopt,
303 comp->cid(), 288 comp->cid(),
304 comp->token_pos(), 289 comp->token_pos(),
305 comp->try_index()); 290 comp->try_index());
306 const String& operator_name = String::ZoneHandle(String::NewSymbol("==")); 291 const String& operator_name = String::ZoneHandle(String::NewSymbol("=="));
307 const int kNumberOfArguments = 2; 292 const int kNumberOfArguments = 2;
308 const Array& kNoArgumentNames = Array::Handle(); 293 const Array& kNoArgumentNames = Array::Handle();
309 const int kNumArgumentsChecked = 2; 294 const int kNumArgumentsChecked = 2;
310 295
311 compiler->GenerateInstanceCall(comp->cid(), 296 compiler->GenerateInstanceCall(comp->cid(),
312 comp->token_pos(), 297 comp->token_pos(),
313 comp->try_index(), 298 comp->try_index(),
314 operator_name, 299 operator_name,
315 kNumberOfArguments, 300 kNumberOfArguments,
316 kNoArgumentNames, 301 kNoArgumentNames,
317 kNumArgumentsChecked); 302 kNumArgumentsChecked);
318 ASSERT(comp->is_fused_with_branch() || (comp->locs()->out().reg() == EAX)); 303 ASSERT(comp->locs()->out().reg() == EAX);
319
320 if (comp->is_fused_with_branch()) {
321 __ CompareObject(EAX, compiler->bool_true());
322 comp->fused_with_branch()->EmitBranchOnCondition(compiler, EQUAL);
323 }
324 } 304 }
325 305
326 306
327 static void EmitEqualityAsPolymorphicCall(FlowGraphCompiler* compiler, 307 static void EmitEqualityAsPolymorphicCall(FlowGraphCompiler* compiler,
328 EqualityCompareComp* comp, 308 const ICData& orig_ic_data,
329 Register left, 309 const LocationSummary& locs,
330 Register right) { 310 BranchInstr* branch,
331 ASSERT(comp->HasICData()); 311 Token::Kind kind,
332 const ICData& ic_data = ICData::Handle(comp->ic_data()->AsUnaryClassChecks()); 312 intptr_t cid,
313 intptr_t token_pos,
314 intptr_t try_index) {
315 const ICData& ic_data = ICData::Handle(orig_ic_data.AsUnaryClassChecks());
333 ASSERT(ic_data.NumberOfChecks() > 0); 316 ASSERT(ic_data.NumberOfChecks() > 0);
334 ASSERT(ic_data.num_args_tested() == 1); 317 ASSERT(ic_data.num_args_tested() == 1);
335 Label* deopt = compiler->AddDeoptStub(comp->cid(), 318 Label* deopt = compiler->AddDeoptStub(cid,
336 comp->token_pos(), 319 token_pos,
337 comp->try_index(), 320 try_index,
338 kDeoptEquality); 321 kDeoptEquality);
322 Register left = locs.in(0).reg();
323 Register right = locs.in(1).reg();
339 __ testl(left, Immediate(kSmiTagMask)); 324 __ testl(left, Immediate(kSmiTagMask));
340 Register temp = comp->locs()->temp(0).reg(); 325 Register temp = locs.temp(0).reg();
341 if (ic_data.GetReceiverClassIdAt(0) == kSmi) { 326 if (ic_data.GetReceiverClassIdAt(0) == kSmi) {
342 Label done, load_class_id; 327 Label done, load_class_id;
343 __ j(NOT_ZERO, &load_class_id, Assembler::kNearJump); 328 __ j(NOT_ZERO, &load_class_id, Assembler::kNearJump);
344 __ movl(temp, Immediate(kSmi)); 329 __ movl(temp, Immediate(kSmi));
345 __ jmp(&done, Assembler::kNearJump); 330 __ jmp(&done, Assembler::kNearJump);
346 __ Bind(&load_class_id); 331 __ Bind(&load_class_id);
347 __ LoadClassId(temp, left); 332 __ LoadClassId(temp, left);
348 __ Bind(&done); 333 __ Bind(&done);
349 } else { 334 } else {
350 __ j(ZERO, deopt); // Smi deopts. 335 __ j(ZERO, deopt); // Smi deopts.
351 __ LoadClassId(temp, left); 336 __ LoadClassId(temp, left);
352 } 337 }
338 Condition cond = (kind == Token::kEQ) ? EQUAL : NOT_EQUAL;
353 Label done; 339 Label done;
354 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { 340 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) {
355 ASSERT((ic_data.GetReceiverClassIdAt(i) != kSmi) || (i == 0)); 341 ASSERT((ic_data.GetReceiverClassIdAt(i) != kSmi) || (i == 0));
356 Label next_test; 342 Label next_test;
357 __ cmpl(temp, Immediate(ic_data.GetReceiverClassIdAt(i))); 343 __ cmpl(temp, Immediate(ic_data.GetReceiverClassIdAt(i)));
358 __ j(NOT_EQUAL, &next_test, Assembler::kNearJump); 344 __ j(NOT_EQUAL, &next_test, Assembler::kNearJump);
359 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(i)); 345 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(i));
360 ObjectStore* object_store = Isolate::Current()->object_store(); 346 ObjectStore* object_store = Isolate::Current()->object_store();
361 if (target.owner() == object_store->object_class()) { 347 if (target.owner() == object_store->object_class()) {
362 // Object.== is same as ===. 348 // Object.== is same as ===.
363 __ Drop(2); 349 __ Drop(2);
364 __ cmpl(left, right); 350 __ cmpl(left, right);
365 if (comp->is_fused_with_branch()) { 351 if (branch != NULL) {
366 comp->fused_with_branch()->EmitBranchOnCondition(compiler, EQUAL); 352 branch->EmitBranchOnCondition(compiler, cond);
367 } else { 353 } else {
368 // This case should be rare. 354 // This case should be rare.
369 Register result = comp->locs()->out().reg(); 355 Register result = locs.out().reg();
370 Label load_true; 356 Label load_true;
371 __ j(EQUAL, &load_true, Assembler::kNearJump); 357 __ j(cond, &load_true, Assembler::kNearJump);
372 __ LoadObject(result, compiler->bool_false()); 358 __ LoadObject(result, compiler->bool_false());
373 __ jmp(&done); 359 __ jmp(&done);
374 __ Bind(&load_true); 360 __ Bind(&load_true);
375 __ LoadObject(result, compiler->bool_true()); 361 __ LoadObject(result, compiler->bool_true());
376 } 362 }
377 } else { 363 } else {
378 const int kNumberOfArguments = 2; 364 const int kNumberOfArguments = 2;
379 const Array& kNoArgumentNames = Array::Handle(); 365 const Array& kNoArgumentNames = Array::Handle();
380 compiler->GenerateStaticCall(comp->cid(), 366 compiler->GenerateStaticCall(cid,
381 comp->token_pos(), 367 token_pos,
382 comp->try_index(), 368 try_index,
383 target, 369 target,
384 kNumberOfArguments, 370 kNumberOfArguments,
385 kNoArgumentNames); 371 kNoArgumentNames);
386 ASSERT(comp->is_fused_with_branch() || 372 if (branch != NULL) {
387 (comp->locs()->out().reg() == EAX));
388 if (comp->is_fused_with_branch()) {
389 __ CompareObject(EAX, compiler->bool_true()); 373 __ CompareObject(EAX, compiler->bool_true());
390 comp->fused_with_branch()->EmitBranchOnCondition(compiler, EQUAL); 374 branch->EmitBranchOnCondition(compiler, cond);
391 } 375 }
392 } 376 }
393 __ jmp(&done); 377 __ jmp(&done);
394 __ Bind(&next_test); 378 __ Bind(&next_test);
395 } 379 }
396 // Fall through leads to deoptimization 380 // Fall through leads to deoptimization
397 __ jmp(deopt); 381 __ jmp(deopt);
398 __ Bind(&done); 382 __ Bind(&done);
399 } 383 }
400 384
401 385
402 // First test if receiver is NULL, in which case === is applied. 386 // First test if receiver is NULL, in which case === is applied.
403 // If type feedback was provided (lists of <class-id, target>), do a 387 // If type feedback was provided (lists of <class-id, target>), do a
404 // type by type check (either === or static call to the operator. 388 // type by type check (either === or static call to the operator.
405 static void EmitGenericEqualityCompare(FlowGraphCompiler* compiler, 389 static void EmitGenericEqualityCompare(FlowGraphCompiler* compiler,
406 EqualityCompareComp* comp) { 390 const LocationSummary& locs,
407 Register left = comp->locs()->in(0).reg(); 391 Token::Kind kind,
408 Register right = comp->locs()->in(1).reg(); 392 BranchInstr* branch,
393 const ICData& ic_data,
394 intptr_t cid,
395 intptr_t token_pos,
396 intptr_t try_index) {
397 ASSERT(!ic_data.IsNull() && (ic_data.NumberOfChecks() > 0));
398 Register left = locs.in(0).reg();
399 Register right = locs.in(1).reg();
409 const Immediate raw_null = 400 const Immediate raw_null =
410 Immediate(reinterpret_cast<intptr_t>(Object::null())); 401 Immediate(reinterpret_cast<intptr_t>(Object::null()));
411 Label done, non_null_compare; 402 Label done, non_null_compare;
412 __ cmpl(left, raw_null); 403 __ cmpl(left, raw_null);
413 __ j(NOT_EQUAL, &non_null_compare, Assembler::kNearJump); 404 __ j(NOT_EQUAL, &non_null_compare, Assembler::kNearJump);
414 // Comparison with NULL is "===". 405 // Comparison with NULL is "===".
415 __ cmpl(left, right); 406 __ cmpl(left, right);
416 if (comp->is_fused_with_branch()) { 407 Condition cond = (kind == Token::kEQ) ? EQUAL : NOT_EQUAL;
417 comp->fused_with_branch()->EmitBranchOnCondition(compiler, EQUAL); 408 if (branch != NULL) {
409 branch->EmitBranchOnCondition(compiler, cond);
418 } else { 410 } else {
419 Register result = comp->locs()->out().reg(); 411 Register result = locs.out().reg();
420 Label load_true; 412 Label load_true;
421 __ j(EQUAL, &load_true, Assembler::kNearJump); 413 __ j(cond, &load_true, Assembler::kNearJump);
422 __ LoadObject(result, compiler->bool_false()); 414 __ LoadObject(result, compiler->bool_false());
423 __ jmp(&done); 415 __ jmp(&done);
424 __ Bind(&load_true); 416 __ Bind(&load_true);
425 __ LoadObject(result, compiler->bool_true()); 417 __ LoadObject(result, compiler->bool_true());
426 } 418 }
427 __ jmp(&done); 419 __ jmp(&done);
428
429 __ Bind(&non_null_compare); // Receiver is not null. 420 __ Bind(&non_null_compare); // Receiver is not null.
430 __ pushl(left); 421 __ pushl(left);
431 __ pushl(right); 422 __ pushl(right);
432 if (comp->HasICData() && (comp->ic_data()->NumberOfChecks() > 0)) { 423 EmitEqualityAsPolymorphicCall(compiler, ic_data, locs, branch, kind,
433 EmitEqualityAsPolymorphicCall(compiler, comp, left, right); 424 cid, token_pos, try_index);
434 } else {
435 EmitEqualityAsInstanceCall(compiler, comp);
436 }
437 __ Bind(&done); 425 __ Bind(&done);
438 } 426 }
439 427
440 428
441 void EqualityCompareComp::EmitNativeCode(FlowGraphCompiler* compiler) { 429 void EqualityCompareComp::EmitNativeCode(FlowGraphCompiler* compiler) {
442 if (receiver_class_id() == kSmi) { 430 if (receiver_class_id() == kSmi) {
443 EmitSmiEqualityCompare(compiler, this); 431 EmitSmiEqualityCompare(compiler, this);
444 return; 432 return;
445 } 433 }
446 if (receiver_class_id() == kDouble) { 434 if (receiver_class_id() == kDouble) {
447 EmitDoubleEqualityCompare(compiler, this); 435 EmitDoubleEqualityCompare(compiler, this);
448 return; 436 return;
449 } 437 }
450 EmitGenericEqualityCompare(compiler, this); 438 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) {
439 EmitGenericEqualityCompare(compiler, *locs(), Token::kEQ, NULL,
440 *ic_data(), cid(), token_pos(), try_index());
441 } else {
442 Register left = locs()->in(0).reg();
443 Register right = locs()->in(1).reg();
444 __ pushl(left);
445 __ pushl(right);
446 EmitEqualityAsInstanceCall(compiler, this);
447 }
451 } 448 }
452 449
453 450
454 LocationSummary* RelationalOpComp::MakeLocationSummary() const { 451 LocationSummary* RelationalOpComp::MakeLocationSummary() const {
455 if ((operands_class_id() == kSmi) || (operands_class_id() == kDouble)) { 452 if ((operands_class_id() == kSmi) || (operands_class_id() == kDouble)) {
456 const intptr_t kNumInputs = 2; 453 const intptr_t kNumInputs = 2;
457 const intptr_t kNumTemps = 1; 454 const intptr_t kNumTemps = 1;
458 LocationSummary* summary = new LocationSummary(kNumInputs, 455 LocationSummary* summary = new LocationSummary(kNumInputs,
459 kNumTemps, 456 kNumTemps,
460 LocationSummary::kNoCall); 457 LocationSummary::kNoCall);
461 summary->set_in(0, Location::RequiresRegister()); 458 summary->set_in(0, Location::RequiresRegister());
462 summary->set_in(1, Location::RequiresRegister()); 459 summary->set_in(1, Location::RequiresRegister());
463 if (!is_fused_with_branch()) { 460 summary->set_out(Location::RequiresRegister());
464 summary->set_out(Location::RequiresRegister());
465 }
466 summary->set_temp(0, Location::RequiresRegister()); 461 summary->set_temp(0, Location::RequiresRegister());
467 return summary; 462 return summary;
468 } 463 }
469 ASSERT(!is_fused_with_branch());
470 ASSERT(operands_class_id() == kObject); 464 ASSERT(operands_class_id() == kObject);
471 return MakeCallSummary(); 465 return MakeCallSummary();
472 } 466 }
473 467
474 468
475 static Condition TokenKindToSmiCondition(Token::Kind kind) { 469 static Condition TokenKindToSmiCondition(Token::Kind kind) {
476 switch (kind) { 470 switch (kind) {
477 case Token::kEQ: return EQUAL; 471 case Token::kEQ: return EQUAL;
478 case Token::kNE: return NOT_EQUAL; 472 case Token::kNE: return NOT_EQUAL;
479 case Token::kLT: return LESS; 473 case Token::kLT: return LESS;
480 case Token::kGT: return GREATER; 474 case Token::kGT: return GREATER;
481 case Token::kLTE: return LESS_EQUAL; 475 case Token::kLTE: return LESS_EQUAL;
482 case Token::kGTE: return GREATER_EQUAL; 476 case Token::kGTE: return GREATER_EQUAL;
483 default: 477 default:
484 UNREACHABLE(); 478 UNREACHABLE();
485 return OVERFLOW; 479 return OVERFLOW;
486 } 480 }
487 } 481 }
488 482
489 483
490 static void EmitSmiRelationalOp(FlowGraphCompiler* compiler, 484 static void EmitSmiComparisonOp(FlowGraphCompiler* compiler,
491 RelationalOpComp* comp) { 485 const LocationSummary& locs,
492 Register left = comp->locs()->in(0).reg(); 486 Token::Kind kind,
493 Register right = comp->locs()->in(1).reg(); 487 BranchInstr* branch,
494 Register temp = comp->locs()->temp(0).reg(); 488 intptr_t cid,
495 Label* deopt = compiler->AddDeoptStub(comp->cid(), 489 intptr_t token_pos,
496 comp->token_pos(), 490 intptr_t try_index) {
497 comp->try_index(), 491 Register left = locs.in(0).reg();
492 Register right = locs.in(1).reg();
493 Register temp = locs.temp(0).reg();
494 Label* deopt = compiler->AddDeoptStub(cid,
495 token_pos,
496 try_index,
498 kDeoptSmiCompareSmi, 497 kDeoptSmiCompareSmi,
499 left, 498 left,
500 right); 499 right);
501 __ movl(temp, left); 500 __ movl(temp, left);
502 __ orl(temp, right); 501 __ orl(temp, right);
503 __ testl(temp, Immediate(kSmiTagMask)); 502 __ testl(temp, Immediate(kSmiTagMask));
504 __ j(NOT_ZERO, deopt); 503 __ j(NOT_ZERO, deopt);
505 504
506 Condition true_condition = TokenKindToSmiCondition(comp->kind()); 505 Condition true_condition = TokenKindToSmiCondition(kind);
507 __ cmpl(left, right); 506 __ cmpl(left, right);
508 507
509 if (comp->is_fused_with_branch()) { 508 if (branch != NULL) {
510 comp->fused_with_branch()->EmitBranchOnCondition(compiler, true_condition); 509 branch->EmitBranchOnCondition(compiler, true_condition);
511 } else { 510 } else {
512 Register result = comp->locs()->out().reg(); 511 Register result = locs.out().reg();
513 Label done, is_true; 512 Label done, is_true;
514 __ j(true_condition, &is_true); 513 __ j(true_condition, &is_true);
515 __ LoadObject(result, compiler->bool_false()); 514 __ LoadObject(result, compiler->bool_false());
516 __ jmp(&done); 515 __ jmp(&done);
517 __ Bind(&is_true); 516 __ Bind(&is_true);
518 __ LoadObject(result, compiler->bool_true()); 517 __ LoadObject(result, compiler->bool_true());
519 __ Bind(&done); 518 __ Bind(&done);
520 } 519 }
521 } 520 }
522 521
523 522
524 static Condition TokenKindToDoubleCondition(Token::Kind kind) { 523 static Condition TokenKindToDoubleCondition(Token::Kind kind) {
525 switch (kind) { 524 switch (kind) {
526 case Token::kEQ: return EQUAL; 525 case Token::kEQ: return EQUAL;
526 case Token::kNE: return NOT_EQUAL;
527 case Token::kLT: return BELOW; 527 case Token::kLT: return BELOW;
528 case Token::kGT: return ABOVE; 528 case Token::kGT: return ABOVE;
529 case Token::kLTE: return BELOW_EQUAL; 529 case Token::kLTE: return BELOW_EQUAL;
530 case Token::kGTE: return ABOVE_EQUAL; 530 case Token::kGTE: return ABOVE_EQUAL;
531 default: 531 default:
532 UNREACHABLE(); 532 UNREACHABLE();
533 return OVERFLOW; 533 return OVERFLOW;
534 } 534 }
535 } 535 }
536 536
537 537
538 static void EmitDoubleRelationalOp(FlowGraphCompiler* compiler, 538 static void EmitDoubleComparisonOp(FlowGraphCompiler* compiler,
539 RelationalOpComp* comp) { 539 const LocationSummary& locs,
540 Register left = comp->locs()->in(0).reg(); 540 Token::Kind kind,
541 Register right = comp->locs()->in(1).reg(); 541 BranchInstr* branch,
542 intptr_t cid,
543 intptr_t token_pos,
544 intptr_t try_index) {
545 Register left = locs.in(0).reg();
546 Register right = locs.in(1).reg();
542 // TODO(srdjan): temp is only needed if a conversion Smi->Double occurs. 547 // TODO(srdjan): temp is only needed if a conversion Smi->Double occurs.
543 Register temp = comp->locs()->temp(0).reg(); 548 Register temp = locs.temp(0).reg();
544 Label* deopt = compiler->AddDeoptStub(comp->cid(), 549 Label* deopt = compiler->AddDeoptStub(cid,
545 comp->token_pos(), 550 token_pos,
546 comp->try_index(), 551 try_index,
547 kDeoptDoubleComparison, 552 kDeoptDoubleComparison,
548 left, 553 left,
549 right); 554 right);
550 compiler->LoadDoubleOrSmiToXmm(XMM0, left, temp, deopt); 555 compiler->LoadDoubleOrSmiToXmm(XMM0, left, temp, deopt);
551 compiler->LoadDoubleOrSmiToXmm(XMM1, right, temp, deopt); 556 compiler->LoadDoubleOrSmiToXmm(XMM1, right, temp, deopt);
552 557
553 Condition true_condition = TokenKindToDoubleCondition(comp->kind()); 558 Condition true_condition = TokenKindToDoubleCondition(kind);
554 if (comp->is_fused_with_branch()) { 559 if (branch != NULL) {
555 compiler->EmitDoubleCompareBranch( 560 compiler->EmitDoubleCompareBranch(
556 true_condition, XMM0, XMM1, comp->fused_with_branch()); 561 true_condition, XMM0, XMM1, branch);
557 } else { 562 } else {
558 compiler->EmitDoubleCompareBool( 563 compiler->EmitDoubleCompareBool(
559 true_condition, XMM0, XMM1, comp->locs()->out().reg()); 564 true_condition, XMM0, XMM1, locs.out().reg());
560 } 565 }
561 } 566 }
562 567
563 568
564 void RelationalOpComp::EmitNativeCode(FlowGraphCompiler* compiler) { 569 void RelationalOpComp::EmitNativeCode(FlowGraphCompiler* compiler) {
565 if (operands_class_id() == kSmi) { 570 if (operands_class_id() == kSmi) {
566 EmitSmiRelationalOp(compiler, this); 571 EmitSmiComparisonOp(compiler, *locs(), kind(), NULL,
572 cid(), token_pos(), try_index());
567 return; 573 return;
568 } 574 }
569 if (operands_class_id() == kDouble) { 575 if (operands_class_id() == kDouble) {
570 EmitDoubleRelationalOp(compiler, this); 576 EmitDoubleComparisonOp(compiler, *locs(), kind(), NULL,
577 cid(), token_pos(), try_index());
571 return; 578 return;
572 } 579 }
573 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { 580 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) {
574 Label* deopt = compiler->AddDeoptStub(cid(), 581 Label* deopt = compiler->AddDeoptStub(cid(),
575 token_pos(), 582 token_pos(),
576 try_index(), 583 try_index(),
577 kDeoptRelationalOp); 584 kDeoptRelationalOp);
578 // Load receiver into EAX, class into EDI. 585 // Load receiver into EAX, class into EDI.
579 Label done; 586 Label done;
580 const intptr_t kNumArguments = 2; 587 const intptr_t kNumArguments = 2;
(...skipping 1440 matching lines...) Expand 10 before | Expand all | Expand 10 after
2021 compiler->GenerateStaticCall(instance_call()->cid(), 2028 compiler->GenerateStaticCall(instance_call()->cid(),
2022 instance_call()->token_pos(), 2029 instance_call()->token_pos(),
2023 instance_call()->try_index(), 2030 instance_call()->try_index(),
2024 target, 2031 target,
2025 instance_call()->ArgumentCount(), 2032 instance_call()->ArgumentCount(),
2026 instance_call()->argument_names()); 2033 instance_call()->argument_names());
2027 } 2034 }
2028 __ Bind(&done); 2035 __ Bind(&done);
2029 } 2036 }
2030 2037
2038
2039 // TODO(srdjan): Move to shared.
2040 static bool ICDataWithBothClassIds(const ICData& ic_data, intptr_t class_id) {
2041 if (ic_data.num_args_tested() != 2) return false;
2042 if (ic_data.NumberOfChecks() != 1) return false;
2043 Function& target = Function::Handle();
2044 GrowableArray<intptr_t> class_ids;
2045 ic_data.GetCheckAt(0, &class_ids, &target);
2046 return (class_ids[0] == class_id) && (class_ids[1] == class_id);
2047 }
2048
2049
2050 LocationSummary* BranchInstr::MakeLocationSummary() const {
2051 if ((kind() == Token::kEQ_STRICT) || (kind() == Token::kNE_STRICT)) {
2052 const int kNumInputs = 2;
2053 const int kNumTemps = 0;
2054 LocationSummary* locs = new LocationSummary(kNumInputs,
2055 kNumTemps,
2056 LocationSummary::kNoCall);
2057 locs->set_in(0, Location::RequiresRegister());
2058 locs->set_in(1, Location::RequiresRegister());
2059 return locs;
2060 }
2061 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) {
2062 if (ICDataWithBothClassIds(*ic_data(), kSmi) ||
2063 ICDataWithBothClassIds(*ic_data(), kDouble)) {
2064 const intptr_t kNumInputs = 2;
2065 const intptr_t kNumTemps = 1;
2066 LocationSummary* summary = new LocationSummary(kNumInputs,
2067 kNumTemps,
2068 LocationSummary::kNoCall);
2069 summary->set_in(0, Location::RequiresRegister());
2070 summary->set_in(1, Location::RequiresRegister());
2071 summary->set_temp(0, Location::RequiresRegister());
2072 return summary;
2073 }
2074 if ((kind() == Token::kEQ) || (kind() == Token::kNE)) {
2075 const intptr_t kNumInputs = 2;
2076 const intptr_t kNumTemps = 1;
2077 LocationSummary* locs = new LocationSummary(kNumInputs,
2078 kNumTemps,
2079 LocationSummary::kCall);
2080 locs->set_in(0, Location::RequiresRegister());
2081 locs->set_in(1, Location::RequiresRegister());
2082 locs->set_temp(0, Location::RequiresRegister());
2083 return locs;
2084 }
2085 // Otherwise polymorphic dispatch.
2086 }
2087 // Call.
2088 LocationSummary* result = new LocationSummary(0, 0, LocationSummary::kCall);
2089 result->set_out(Location::RegisterLocation(EAX));
2090 return result;
2091 }
2092
2093
2094 void BranchInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
2095 if ((kind() == Token::kEQ_STRICT) || (kind() == Token::kNE_STRICT)) {
2096 Register left = locs()->in(0).reg();
2097 Register right = locs()->in(1).reg();
2098 __ cmpl(left, right);
2099 Condition cond = (kind() == Token::kEQ_STRICT) ? EQUAL : NOT_EQUAL;
2100 EmitBranchOnCondition(compiler, cond);
2101 return;
2102 }
2103 // Relational or equality.
2104 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) {
2105 if (ICDataWithBothClassIds(*ic_data(), kSmi)) {
2106 EmitSmiComparisonOp(compiler, *locs(), kind(), this,
2107 cid(), token_pos(), try_index());
2108 return;
2109 }
2110 if (ICDataWithBothClassIds(*ic_data(), kDouble)) {
2111 EmitDoubleComparisonOp(compiler, *locs(), kind(), this,
2112 cid(), token_pos(), try_index());
2113 return;
2114 }
2115 // TODO(srdjan): Add Smi/Double, Double/Smi comparisons.
2116 if ((kind() == Token::kEQ) || (kind() == Token::kNE)) {
2117 EmitGenericEqualityCompare(compiler, *locs(), kind(), this, *ic_data(),
2118 cid(), token_pos(), try_index());
2119 return;
2120 }
2121 // Otherwise polymorphic dispatch?
2122 }
2123 // Not equal is always split into '==' and negate,
2124 Condition branch_condition = (kind() == Token::kNE) ? NOT_EQUAL : EQUAL;
2125 Token::Kind call_kind = (kind() == Token::kNE) ? Token::kEQ : kind();
2126 const String& function_name =
2127 String::ZoneHandle(String::NewSymbol(Token::Str(call_kind)));
2128 compiler->AddCurrentDescriptor(PcDescriptors::kDeopt,
2129 cid(),
2130 token_pos(),
2131 try_index());
2132 const intptr_t kNumArguments = 2;
2133 const intptr_t kNumArgsChecked = 2; // Type-feedback.
2134 compiler->GenerateInstanceCall(cid(),
2135 token_pos(),
2136 try_index(),
2137 function_name,
2138 kNumArguments,
2139 Array::ZoneHandle(), // No optional arguments.
2140 kNumArgsChecked);
2141 ASSERT(locs()->out().reg() == EAX);
2142 __ CompareObject(locs()->out().reg(), compiler->bool_true());
2143 EmitBranchOnCondition(compiler, branch_condition);
2144 }
2145
2031 } // namespace dart 2146 } // namespace dart
2032 2147
2033 #undef __ 2148 #undef __
2034 2149
2035 #endif // defined TARGET_ARCH_X64 2150 #endif // defined TARGET_ARCH_X64
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698