| OLD | NEW |
| 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 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 193 // We should never return here. | 193 // We should never return here. |
| 194 __ int3(); | 194 __ int3(); |
| 195 | 195 |
| 196 __ Bind(&done); | 196 __ Bind(&done); |
| 197 ASSERT(obj == result); | 197 ASSERT(obj == result); |
| 198 } | 198 } |
| 199 | 199 |
| 200 | 200 |
| 201 LocationSummary* EqualityCompareComp::MakeLocationSummary() const { | 201 LocationSummary* EqualityCompareComp::MakeLocationSummary() const { |
| 202 const intptr_t kNumInputs = 2; | 202 const intptr_t kNumInputs = 2; |
| 203 if (HasICData() && | 203 if (receiver_class_id() != kObject) { |
| 204 (ic_data()->NumberOfChecks() == 1) && | 204 ASSERT((receiver_class_id() == kSmi) || (receiver_class_id() == kDouble)); |
| 205 (ic_data()->GetReceiverClassIdAt(0) == kSmi)) { | 205 // No temporary register needed for double comparison. |
| 206 const intptr_t kNumTemps = 1; | 206 const intptr_t kNumTemps = (receiver_class_id() == kSmi) ? 1 : 0; |
| 207 LocationSummary* locs = new LocationSummary(kNumInputs, | 207 LocationSummary* locs = new LocationSummary(kNumInputs, |
| 208 kNumTemps, | 208 kNumTemps, |
| 209 LocationSummary::kNoCall); | 209 LocationSummary::kNoCall); |
| 210 locs->set_in(0, Location::RequiresRegister()); | 210 locs->set_in(0, Location::RequiresRegister()); |
| 211 locs->set_in(1, Location::RequiresRegister()); | 211 locs->set_in(1, Location::RequiresRegister()); |
| 212 locs->set_temp(0, Location::RequiresRegister()); | 212 if (receiver_class_id() == kSmi) { |
| 213 locs->set_temp(0, Location::RequiresRegister()); |
| 214 } |
| 213 if (!is_fused_with_branch()) { | 215 if (!is_fused_with_branch()) { |
| 214 locs->set_out(Location::RequiresRegister()); | 216 locs->set_out(Location::RequiresRegister()); |
| 215 } | 217 } |
| 216 return locs; | 218 return locs; |
| 217 } | 219 } |
| 218 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { | 220 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { |
| 219 const intptr_t kNumTemps = 1; | 221 const intptr_t kNumTemps = 1; |
| 220 LocationSummary* locs = new LocationSummary(kNumInputs, | 222 LocationSummary* locs = new LocationSummary(kNumInputs, |
| 221 kNumTemps, | 223 kNumTemps, |
| 222 LocationSummary::kCall); | 224 LocationSummary::kCall); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 234 LocationSummary::kCall); | 236 LocationSummary::kCall); |
| 235 locs->set_in(0, Location::RequiresRegister()); | 237 locs->set_in(0, Location::RequiresRegister()); |
| 236 locs->set_in(1, Location::RequiresRegister()); | 238 locs->set_in(1, Location::RequiresRegister()); |
| 237 if (!is_fused_with_branch()) { | 239 if (!is_fused_with_branch()) { |
| 238 locs->set_out(Location::RegisterLocation(RAX)); | 240 locs->set_out(Location::RegisterLocation(RAX)); |
| 239 } | 241 } |
| 240 return locs; | 242 return locs; |
| 241 } | 243 } |
| 242 | 244 |
| 243 | 245 |
| 246 // Optional integer arguments can often be null. Null is not collected |
| 247 // by IC data. TODO(srdjan): Shall we collect null classes in ICData as well? |
| 244 static void EmitSmiEqualityCompare(FlowGraphCompiler* compiler, | 248 static void EmitSmiEqualityCompare(FlowGraphCompiler* compiler, |
| 245 EqualityCompareComp* comp) { | 249 EqualityCompareComp* comp) { |
| 246 Register left = comp->locs()->in(0).reg(); | 250 Register left = comp->locs()->in(0).reg(); |
| 247 Register right = comp->locs()->in(1).reg(); | 251 Register right = comp->locs()->in(1).reg(); |
| 248 Register temp = comp->locs()->temp(0).reg(); | 252 Register temp = comp->locs()->temp(0).reg(); |
| 249 Label* deopt = compiler->AddDeoptStub(comp->cid(), | 253 Label* deopt = compiler->AddDeoptStub(comp->cid(), |
| 250 comp->token_pos(), | 254 comp->token_pos(), |
| 251 comp->try_index(), | 255 comp->try_index(), |
| 252 kDeoptSmiCompareSmis, | 256 kDeoptSmiCompareSmi, |
| 253 left, | 257 left, |
| 254 right); | 258 right); |
| 255 // TODO(srdjan): Should we always include NULL test (common case)? | |
| 256 __ movq(temp, left); | 259 __ movq(temp, left); |
| 257 __ orq(temp, right); | 260 __ orq(temp, right); |
| 258 __ testq(temp, Immediate(kSmiTagMask)); | 261 __ testq(temp, Immediate(kSmiTagMask)); |
| 259 __ j(NOT_ZERO, deopt); | 262 __ j(NOT_ZERO, deopt); |
| 260 __ cmpq(left, right); | 263 __ cmpq(left, right); |
| 261 if (comp->is_fused_with_branch()) { | 264 if (comp->is_fused_with_branch()) { |
| 262 comp->fused_with_branch()->EmitBranchOnCondition(compiler, EQUAL); | 265 comp->fused_with_branch()->EmitBranchOnCondition(compiler, EQUAL); |
| 263 } else { | 266 } else { |
| 264 Register result = comp->locs()->out().reg(); | 267 Register result = comp->locs()->out().reg(); |
| 265 Label load_true, done; | 268 Label load_true, done; |
| 266 __ j(EQUAL, &load_true, Assembler::kNearJump); | 269 __ j(EQUAL, &load_true, Assembler::kNearJump); |
| 267 __ LoadObject(result, compiler->bool_false()); | 270 __ LoadObject(result, compiler->bool_false()); |
| 268 __ jmp(&done, Assembler::kNearJump); | 271 __ jmp(&done, Assembler::kNearJump); |
| 269 __ Bind(&load_true); | 272 __ Bind(&load_true); |
| 270 __ LoadObject(result, compiler->bool_true()); | 273 __ LoadObject(result, compiler->bool_true()); |
| 271 __ Bind(&done); | 274 __ Bind(&done); |
| 272 } | 275 } |
| 273 } | 276 } |
| 274 | 277 |
| 275 | 278 |
| 279 // TODO(srdjan): Add support for mixed Smi/Double equality |
| 280 // (see LoadDoubleOrSmiToXmm). |
| 281 static void EmitDoubleEqualityCompare(FlowGraphCompiler* compiler, |
| 282 EqualityCompareComp* comp) { |
| 283 Register left = comp->locs()->in(0).reg(); |
| 284 Register right = comp->locs()->in(1).reg(); |
| 285 Label* deopt = compiler->AddDeoptStub(comp->cid(), |
| 286 comp->token_pos(), |
| 287 comp->try_index(), |
| 288 kDeoptDoubleCompareDouble, |
| 289 left, |
| 290 right); |
| 291 __ CompareClassId(left, kDouble); |
| 292 __ j(NOT_EQUAL, deopt); |
| 293 __ CompareClassId(right, kDouble); |
| 294 __ j(NOT_EQUAL, deopt); |
| 295 __ movsd(XMM0, FieldAddress(left, Double::value_offset())); |
| 296 __ movsd(XMM1, FieldAddress(right, Double::value_offset())); |
| 297 if (comp->is_fused_with_branch()) { |
| 298 compiler->EmitDoubleCompareBranch( |
| 299 EQUAL, XMM0, XMM1, comp->fused_with_branch()); |
| 300 } else { |
| 301 compiler->EmitDoubleCompareBool( |
| 302 EQUAL, XMM0, XMM1, comp->locs()->out().reg()); |
| 303 } |
| 304 } |
| 305 |
| 306 |
| 276 static void EmitEqualityAsInstanceCall(FlowGraphCompiler* compiler, | 307 static void EmitEqualityAsInstanceCall(FlowGraphCompiler* compiler, |
| 277 EqualityCompareComp* comp) { | 308 EqualityCompareComp* comp) { |
| 278 compiler->AddCurrentDescriptor(PcDescriptors::kDeopt, | 309 compiler->AddCurrentDescriptor(PcDescriptors::kDeopt, |
| 279 comp->cid(), | 310 comp->cid(), |
| 280 comp->token_pos(), | 311 comp->token_pos(), |
| 281 comp->try_index()); | 312 comp->try_index()); |
| 282 const String& operator_name = String::ZoneHandle(String::NewSymbol("==")); | 313 const String& operator_name = String::ZoneHandle(String::NewSymbol("==")); |
| 283 const int kNumberOfArguments = 2; | 314 const int kNumberOfArguments = 2; |
| 284 const Array& kNoArgumentNames = Array::Handle(); | 315 const Array& kNoArgumentNames = Array::Handle(); |
| 285 const int kNumArgumentsChecked = 2; | 316 const int kNumArgumentsChecked = 2; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 298 comp->fused_with_branch()->EmitBranchOnCondition(compiler, EQUAL); | 329 comp->fused_with_branch()->EmitBranchOnCondition(compiler, EQUAL); |
| 299 } | 330 } |
| 300 } | 331 } |
| 301 | 332 |
| 302 | 333 |
| 303 static void EmitEqualityAsPolymorphicCall(FlowGraphCompiler* compiler, | 334 static void EmitEqualityAsPolymorphicCall(FlowGraphCompiler* compiler, |
| 304 EqualityCompareComp* comp, | 335 EqualityCompareComp* comp, |
| 305 Register left, | 336 Register left, |
| 306 Register right) { | 337 Register right) { |
| 307 ASSERT(comp->HasICData()); | 338 ASSERT(comp->HasICData()); |
| 308 const ICData& ic_data = *comp->ic_data(); | 339 const ICData& ic_data = ICData::Handle(comp->ic_data()->AsUnaryClassChecks()); |
| 309 ASSERT(ic_data.NumberOfChecks() > 0); | 340 ASSERT(ic_data.NumberOfChecks() > 0); |
| 310 ASSERT(ic_data.num_args_tested() == 1); | 341 ASSERT(ic_data.num_args_tested() == 1); |
| 311 Label* deopt = compiler->AddDeoptStub(comp->cid(), | 342 Label* deopt = compiler->AddDeoptStub(comp->cid(), |
| 312 comp->token_pos(), | 343 comp->token_pos(), |
| 313 comp->try_index(), | 344 comp->try_index(), |
| 314 kDeoptEquality); | 345 kDeoptEquality); |
| 315 __ testq(left, Immediate(kSmiTagMask)); | 346 __ testq(left, Immediate(kSmiTagMask)); |
| 316 Register temp = comp->locs()->temp(0).reg(); | 347 Register temp = comp->locs()->temp(0).reg(); |
| 317 if (ic_data.GetReceiverClassIdAt(0) == kSmi) { | 348 if (ic_data.GetReceiverClassIdAt(0) == kSmi) { |
| 318 Label done, load_class_id; | 349 Label done, load_class_id; |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 408 if (comp->HasICData() && (comp->ic_data()->NumberOfChecks() > 0)) { | 439 if (comp->HasICData() && (comp->ic_data()->NumberOfChecks() > 0)) { |
| 409 EmitEqualityAsPolymorphicCall(compiler, comp, left, right); | 440 EmitEqualityAsPolymorphicCall(compiler, comp, left, right); |
| 410 } else { | 441 } else { |
| 411 EmitEqualityAsInstanceCall(compiler, comp); | 442 EmitEqualityAsInstanceCall(compiler, comp); |
| 412 } | 443 } |
| 413 __ Bind(&done); | 444 __ Bind(&done); |
| 414 } | 445 } |
| 415 | 446 |
| 416 | 447 |
| 417 void EqualityCompareComp::EmitNativeCode(FlowGraphCompiler* compiler) { | 448 void EqualityCompareComp::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 418 if (HasICData() && | 449 if (receiver_class_id() == kSmi) { |
| 419 (ic_data()->NumberOfChecks() == 1) && | |
| 420 (ic_data()->GetReceiverClassIdAt(0) == kSmi)) { | |
| 421 EmitSmiEqualityCompare(compiler, this); | 450 EmitSmiEqualityCompare(compiler, this); |
| 422 return; | 451 return; |
| 423 } | 452 } |
| 453 if (receiver_class_id() == kDouble) { |
| 454 EmitDoubleEqualityCompare(compiler, this); |
| 455 return; |
| 456 } |
| 424 EmitGenericEqualityCompare(compiler, this); | 457 EmitGenericEqualityCompare(compiler, this); |
| 425 } | 458 } |
| 426 | 459 |
| 427 | 460 |
| 428 LocationSummary* RelationalOpComp::MakeLocationSummary() const { | 461 LocationSummary* RelationalOpComp::MakeLocationSummary() const { |
| 429 if (operands_class_id() == kSmi || operands_class_id() == kDouble) { | 462 if (operands_class_id() == kSmi || operands_class_id() == kDouble) { |
| 430 const intptr_t kNumInputs = 2; | 463 const intptr_t kNumInputs = 2; |
| 431 const intptr_t kNumTemps = 1; | 464 const intptr_t kNumTemps = 1; |
| 432 LocationSummary* summary = new LocationSummary(kNumInputs, | 465 LocationSummary* summary = new LocationSummary(kNumInputs, |
| 433 kNumTemps, | 466 kNumTemps, |
| (...skipping 28 matching lines...) Expand all Loading... |
| 462 | 495 |
| 463 | 496 |
| 464 static void EmitSmiRelationalOp(FlowGraphCompiler* compiler, | 497 static void EmitSmiRelationalOp(FlowGraphCompiler* compiler, |
| 465 RelationalOpComp* comp) { | 498 RelationalOpComp* comp) { |
| 466 Register left = comp->locs()->in(0).reg(); | 499 Register left = comp->locs()->in(0).reg(); |
| 467 Register right = comp->locs()->in(1).reg(); | 500 Register right = comp->locs()->in(1).reg(); |
| 468 Register temp = comp->locs()->temp(0).reg(); | 501 Register temp = comp->locs()->temp(0).reg(); |
| 469 Label* deopt = compiler->AddDeoptStub(comp->cid(), | 502 Label* deopt = compiler->AddDeoptStub(comp->cid(), |
| 470 comp->token_pos(), | 503 comp->token_pos(), |
| 471 comp->try_index(), | 504 comp->try_index(), |
| 472 kDeoptSmiCompareSmis, | 505 kDeoptSmiCompareSmi, |
| 473 left, | 506 left, |
| 474 right); | 507 right); |
| 475 __ movq(temp, left); | 508 __ movq(temp, left); |
| 476 __ orq(temp, right); | 509 __ orq(temp, right); |
| 477 __ testq(temp, Immediate(kSmiTagMask)); | 510 __ testq(temp, Immediate(kSmiTagMask)); |
| 478 __ j(NOT_ZERO, deopt); | 511 __ j(NOT_ZERO, deopt); |
| 479 | 512 |
| 480 Condition true_condition = TokenKindToSmiCondition(comp->kind()); | 513 Condition true_condition = TokenKindToSmiCondition(comp->kind()); |
| 481 __ cmpq(left, right); | 514 __ cmpq(left, right); |
| 482 | 515 |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 518 Label* deopt = compiler->AddDeoptStub(comp->cid(), | 551 Label* deopt = compiler->AddDeoptStub(comp->cid(), |
| 519 comp->token_pos(), | 552 comp->token_pos(), |
| 520 comp->try_index(), | 553 comp->try_index(), |
| 521 kDeoptDoubleComparison, | 554 kDeoptDoubleComparison, |
| 522 left, | 555 left, |
| 523 right); | 556 right); |
| 524 compiler->LoadDoubleOrSmiToXmm(XMM0, left, temp, deopt); | 557 compiler->LoadDoubleOrSmiToXmm(XMM0, left, temp, deopt); |
| 525 compiler->LoadDoubleOrSmiToXmm(XMM1, right, temp, deopt); | 558 compiler->LoadDoubleOrSmiToXmm(XMM1, right, temp, deopt); |
| 526 | 559 |
| 527 Condition true_condition = TokenKindToDoubleCondition(comp->kind()); | 560 Condition true_condition = TokenKindToDoubleCondition(comp->kind()); |
| 528 __ comisd(XMM0, XMM1); | |
| 529 | |
| 530 if (comp->is_fused_with_branch()) { | 561 if (comp->is_fused_with_branch()) { |
| 531 BranchInstr* branch = comp->fused_with_branch(); | 562 compiler->EmitDoubleCompareBranch( |
| 532 BlockEntryInstr* nan_result = branch->is_negated() ? | 563 true_condition, XMM0, XMM1, comp->fused_with_branch()); |
| 533 branch->true_successor() : branch->false_successor(); | |
| 534 __ j(PARITY_EVEN, compiler->GetBlockLabel(nan_result)); | |
| 535 branch->EmitBranchOnCondition(compiler, true_condition); | |
| 536 } else { | 564 } else { |
| 537 Register result = comp->locs()->out().reg(); | 565 compiler->EmitDoubleCompareBool( |
| 538 Label is_false, is_true, done; | 566 true_condition, XMM0, XMM1, comp->locs()->out().reg()); |
| 539 __ j(PARITY_EVEN, &is_false, Assembler::kNearJump); // NaN -> false; | |
| 540 __ j(true_condition, &is_true, Assembler::kNearJump); | |
| 541 __ Bind(&is_false); | |
| 542 __ LoadObject(result, compiler->bool_false()); | |
| 543 __ jmp(&done); | |
| 544 __ Bind(&is_true); | |
| 545 __ LoadObject(result, compiler->bool_true()); | |
| 546 __ Bind(&done); | |
| 547 } | 567 } |
| 548 } | 568 } |
| 549 | 569 |
| 550 | 570 |
| 551 void RelationalOpComp::EmitNativeCode(FlowGraphCompiler* compiler) { | 571 void RelationalOpComp::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 552 if (operands_class_id() == kSmi) { | 572 if (operands_class_id() == kSmi) { |
| 553 EmitSmiRelationalOp(compiler, this); | 573 EmitSmiRelationalOp(compiler, this); |
| 554 return; | 574 return; |
| 555 } | 575 } |
| 556 if (operands_class_id() == kDouble) { | 576 if (operands_class_id() == kDouble) { |
| (...skipping 1402 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1959 } | 1979 } |
| 1960 __ Bind(&done); | 1980 __ Bind(&done); |
| 1961 } | 1981 } |
| 1962 | 1982 |
| 1963 | 1983 |
| 1964 } // namespace dart | 1984 } // namespace dart |
| 1965 | 1985 |
| 1966 #undef __ | 1986 #undef __ |
| 1967 | 1987 |
| 1968 #endif // defined TARGET_ARCH_X64 | 1988 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |