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 |