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

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

Powered by Google App Engine
This is Rietveld 408576698