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_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 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
185 // We should never return here. | 185 // We should never return here. |
186 __ int3(); | 186 __ int3(); |
187 | 187 |
188 __ Bind(&done); | 188 __ Bind(&done); |
189 ASSERT(obj == result); | 189 ASSERT(obj == result); |
190 } | 190 } |
191 | 191 |
192 | 192 |
193 LocationSummary* EqualityCompareComp::MakeLocationSummary() const { | 193 LocationSummary* EqualityCompareComp::MakeLocationSummary() const { |
194 const intptr_t kNumInputs = 2; | 194 const intptr_t kNumInputs = 2; |
195 if (HasICData() && | 195 if (receiver_class_id() != kObject) { |
196 (ic_data()->NumberOfChecks() == 1) && | 196 ASSERT((receiver_class_id() == kSmi) || (receiver_class_id() == kDouble)); |
197 (ic_data()->GetReceiverClassIdAt(0) == kSmi)) { | |
198 const intptr_t kNumTemps = 1; | 197 const intptr_t kNumTemps = 1; |
199 LocationSummary* locs = new LocationSummary(kNumInputs, | 198 LocationSummary* locs = new LocationSummary(kNumInputs, |
200 kNumTemps, | 199 kNumTemps, |
201 LocationSummary::kNoCall); | 200 LocationSummary::kNoCall); |
202 locs->set_in(0, Location::RequiresRegister()); | 201 locs->set_in(0, Location::RequiresRegister()); |
203 locs->set_in(1, Location::RequiresRegister()); | 202 locs->set_in(1, Location::RequiresRegister()); |
204 locs->set_temp(0, Location::RequiresRegister()); | 203 locs->set_temp(0, Location::RequiresRegister()); |
205 if (!is_fused_with_branch()) { | 204 if (!is_fused_with_branch()) { |
206 locs->set_out(Location::RequiresRegister()); | 205 locs->set_out(Location::RequiresRegister()); |
207 } | 206 } |
(...skipping 18 matching lines...) Expand all Loading... |
226 LocationSummary::kCall); | 225 LocationSummary::kCall); |
227 locs->set_in(0, Location::RequiresRegister()); | 226 locs->set_in(0, Location::RequiresRegister()); |
228 locs->set_in(1, Location::RequiresRegister()); | 227 locs->set_in(1, Location::RequiresRegister()); |
229 if (!is_fused_with_branch()) { | 228 if (!is_fused_with_branch()) { |
230 locs->set_out(Location::RegisterLocation(EAX)); | 229 locs->set_out(Location::RegisterLocation(EAX)); |
231 } | 230 } |
232 return locs; | 231 return locs; |
233 } | 232 } |
234 | 233 |
235 | 234 |
| 235 // Optional integer arguments can often be null. Null is not collected |
| 236 // by IC data. TODO(srdjan): Shall we collect null classes in ICData as well? |
236 static void EmitSmiEqualityCompare(FlowGraphCompiler* compiler, | 237 static void EmitSmiEqualityCompare(FlowGraphCompiler* compiler, |
237 EqualityCompareComp* comp) { | 238 EqualityCompareComp* comp) { |
238 Register left = comp->locs()->in(0).reg(); | 239 Register left = comp->locs()->in(0).reg(); |
239 Register right = comp->locs()->in(1).reg(); | 240 Register right = comp->locs()->in(1).reg(); |
240 Register temp = comp->locs()->temp(0).reg(); | 241 Register temp = comp->locs()->temp(0).reg(); |
241 Label* deopt = compiler->AddDeoptStub(comp->cid(), | 242 Label* deopt = compiler->AddDeoptStub(comp->cid(), |
242 comp->token_pos(), | 243 comp->token_pos(), |
243 comp->try_index(), | 244 comp->try_index(), |
244 kDeoptSmiCompareSmis, | 245 kDeoptSmiCompareSmi, |
245 left, | 246 left, |
246 right); | 247 right); |
247 // TODO(srdjan): Should we always include NULL test (common case)? | |
248 __ movl(temp, left); | 248 __ movl(temp, left); |
249 __ orl(temp, right); | 249 __ orl(temp, right); |
250 __ testl(temp, Immediate(kSmiTagMask)); | 250 __ testl(temp, Immediate(kSmiTagMask)); |
251 __ j(NOT_ZERO, deopt); | 251 __ j(NOT_ZERO, deopt); |
252 __ cmpl(left, right); | 252 __ cmpl(left, right); |
253 if (comp->is_fused_with_branch()) { | 253 if (comp->is_fused_with_branch()) { |
254 comp->fused_with_branch()->EmitBranchOnCondition(compiler, EQUAL); | 254 comp->fused_with_branch()->EmitBranchOnCondition(compiler, EQUAL); |
255 } else { | 255 } else { |
256 Register result = comp->locs()->out().reg(); | 256 Register result = comp->locs()->out().reg(); |
257 Label load_true, done; | 257 Label load_true, done; |
258 __ j(EQUAL, &load_true, Assembler::kNearJump); | 258 __ j(EQUAL, &load_true, Assembler::kNearJump); |
259 __ LoadObject(result, compiler->bool_false()); | 259 __ LoadObject(result, compiler->bool_false()); |
260 __ jmp(&done, Assembler::kNearJump); | 260 __ jmp(&done, Assembler::kNearJump); |
261 __ Bind(&load_true); | 261 __ Bind(&load_true); |
262 __ LoadObject(result, compiler->bool_true()); | 262 __ LoadObject(result, compiler->bool_true()); |
263 __ Bind(&done); | 263 __ Bind(&done); |
264 } | 264 } |
265 } | 265 } |
266 | 266 |
267 | 267 |
| 268 // TODO(srdjan): Add support for mixed Smi/Double equality |
| 269 // (see LoadDoubleOrSmiToXmm). |
| 270 static void EmitDoubleEqualityCompare(FlowGraphCompiler* compiler, |
| 271 EqualityCompareComp* comp) { |
| 272 Register left = comp->locs()->in(0).reg(); |
| 273 Register right = comp->locs()->in(1).reg(); |
| 274 Register temp = comp->locs()->temp(0).reg(); |
| 275 Label* deopt = compiler->AddDeoptStub(comp->cid(), |
| 276 comp->token_pos(), |
| 277 comp->try_index(), |
| 278 kDeoptDoubleCompareDouble, |
| 279 left, |
| 280 right); |
| 281 Label done, is_false, is_true; |
| 282 __ CompareClassId(left, kDouble, temp); |
| 283 __ j(NOT_EQUAL, deopt); |
| 284 __ CompareClassId(right, kDouble, temp); |
| 285 __ j(NOT_EQUAL, deopt); |
| 286 __ movsd(XMM0, FieldAddress(left, Double::value_offset())); |
| 287 __ movsd(XMM1, FieldAddress(right, Double::value_offset())); |
| 288 if (comp->is_fused_with_branch()) { |
| 289 compiler->EmitDoubleCompareBranch( |
| 290 EQUAL, XMM0, XMM1, comp->fused_with_branch()); |
| 291 } else { |
| 292 compiler->EmitDoubleCompareBool( |
| 293 EQUAL, XMM0, XMM1, comp->locs()->out().reg()); |
| 294 } |
| 295 } |
| 296 |
| 297 |
268 static void EmitEqualityAsInstanceCall(FlowGraphCompiler* compiler, | 298 static void EmitEqualityAsInstanceCall(FlowGraphCompiler* compiler, |
269 EqualityCompareComp* comp) { | 299 EqualityCompareComp* comp) { |
270 compiler->AddCurrentDescriptor(PcDescriptors::kDeopt, | 300 compiler->AddCurrentDescriptor(PcDescriptors::kDeopt, |
271 comp->cid(), | 301 comp->cid(), |
272 comp->token_pos(), | 302 comp->token_pos(), |
273 comp->try_index()); | 303 comp->try_index()); |
274 const String& operator_name = String::ZoneHandle(String::NewSymbol("==")); | 304 const String& operator_name = String::ZoneHandle(String::NewSymbol("==")); |
275 const int kNumberOfArguments = 2; | 305 const int kNumberOfArguments = 2; |
276 const Array& kNoArgumentNames = Array::Handle(); | 306 const Array& kNoArgumentNames = Array::Handle(); |
277 const int kNumArgumentsChecked = 2; | 307 const int kNumArgumentsChecked = 2; |
(...skipping 12 matching lines...) Expand all Loading... |
290 comp->fused_with_branch()->EmitBranchOnCondition(compiler, EQUAL); | 320 comp->fused_with_branch()->EmitBranchOnCondition(compiler, EQUAL); |
291 } | 321 } |
292 } | 322 } |
293 | 323 |
294 | 324 |
295 static void EmitEqualityAsPolymorphicCall(FlowGraphCompiler* compiler, | 325 static void EmitEqualityAsPolymorphicCall(FlowGraphCompiler* compiler, |
296 EqualityCompareComp* comp, | 326 EqualityCompareComp* comp, |
297 Register left, | 327 Register left, |
298 Register right) { | 328 Register right) { |
299 ASSERT(comp->HasICData()); | 329 ASSERT(comp->HasICData()); |
300 const ICData& ic_data = *comp->ic_data(); | 330 const ICData& ic_data = ICData::Handle(comp->ic_data()->AsUnaryClassChecks()); |
301 ASSERT(ic_data.NumberOfChecks() > 0); | 331 ASSERT(ic_data.NumberOfChecks() > 0); |
302 ASSERT(ic_data.num_args_tested() == 1); | 332 ASSERT(ic_data.num_args_tested() == 1); |
303 Label* deopt = compiler->AddDeoptStub(comp->cid(), | 333 Label* deopt = compiler->AddDeoptStub(comp->cid(), |
304 comp->token_pos(), | 334 comp->token_pos(), |
305 comp->try_index(), | 335 comp->try_index(), |
306 kDeoptEquality); | 336 kDeoptEquality); |
307 __ testl(left, Immediate(kSmiTagMask)); | 337 __ testl(left, Immediate(kSmiTagMask)); |
308 Register temp = comp->locs()->temp(0).reg(); | 338 Register temp = comp->locs()->temp(0).reg(); |
309 if (ic_data.GetReceiverClassIdAt(0) == kSmi) { | 339 if (ic_data.GetReceiverClassIdAt(0) == kSmi) { |
310 Label done, load_class_id; | 340 Label done, load_class_id; |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
400 if (comp->HasICData() && (comp->ic_data()->NumberOfChecks() > 0)) { | 430 if (comp->HasICData() && (comp->ic_data()->NumberOfChecks() > 0)) { |
401 EmitEqualityAsPolymorphicCall(compiler, comp, left, right); | 431 EmitEqualityAsPolymorphicCall(compiler, comp, left, right); |
402 } else { | 432 } else { |
403 EmitEqualityAsInstanceCall(compiler, comp); | 433 EmitEqualityAsInstanceCall(compiler, comp); |
404 } | 434 } |
405 __ Bind(&done); | 435 __ Bind(&done); |
406 } | 436 } |
407 | 437 |
408 | 438 |
409 void EqualityCompareComp::EmitNativeCode(FlowGraphCompiler* compiler) { | 439 void EqualityCompareComp::EmitNativeCode(FlowGraphCompiler* compiler) { |
410 if (HasICData() && | 440 if (receiver_class_id() == kSmi) { |
411 (ic_data()->NumberOfChecks() == 1) && | |
412 (ic_data()->GetReceiverClassIdAt(0) == kSmi)) { | |
413 EmitSmiEqualityCompare(compiler, this); | 441 EmitSmiEqualityCompare(compiler, this); |
414 return; | 442 return; |
415 } | 443 } |
| 444 if (receiver_class_id() == kDouble) { |
| 445 EmitDoubleEqualityCompare(compiler, this); |
| 446 return; |
| 447 } |
416 EmitGenericEqualityCompare(compiler, this); | 448 EmitGenericEqualityCompare(compiler, this); |
417 } | 449 } |
418 | 450 |
419 | 451 |
420 LocationSummary* RelationalOpComp::MakeLocationSummary() const { | 452 LocationSummary* RelationalOpComp::MakeLocationSummary() const { |
421 if ((operands_class_id() == kSmi) || (operands_class_id() == kDouble)) { | 453 if ((operands_class_id() == kSmi) || (operands_class_id() == kDouble)) { |
422 const intptr_t kNumInputs = 2; | 454 const intptr_t kNumInputs = 2; |
423 const intptr_t kNumTemps = 1; | 455 const intptr_t kNumTemps = 1; |
424 LocationSummary* summary = new LocationSummary(kNumInputs, | 456 LocationSummary* summary = new LocationSummary(kNumInputs, |
425 kNumTemps, | 457 kNumTemps, |
(...skipping 28 matching lines...) Expand all Loading... |
454 | 486 |
455 | 487 |
456 static void EmitSmiRelationalOp(FlowGraphCompiler* compiler, | 488 static void EmitSmiRelationalOp(FlowGraphCompiler* compiler, |
457 RelationalOpComp* comp) { | 489 RelationalOpComp* comp) { |
458 Register left = comp->locs()->in(0).reg(); | 490 Register left = comp->locs()->in(0).reg(); |
459 Register right = comp->locs()->in(1).reg(); | 491 Register right = comp->locs()->in(1).reg(); |
460 Register temp = comp->locs()->temp(0).reg(); | 492 Register temp = comp->locs()->temp(0).reg(); |
461 Label* deopt = compiler->AddDeoptStub(comp->cid(), | 493 Label* deopt = compiler->AddDeoptStub(comp->cid(), |
462 comp->token_pos(), | 494 comp->token_pos(), |
463 comp->try_index(), | 495 comp->try_index(), |
464 kDeoptSmiCompareSmis, | 496 kDeoptSmiCompareSmi, |
465 left, | 497 left, |
466 right); | 498 right); |
467 __ movl(temp, left); | 499 __ movl(temp, left); |
468 __ orl(temp, right); | 500 __ orl(temp, right); |
469 __ testl(temp, Immediate(kSmiTagMask)); | 501 __ testl(temp, Immediate(kSmiTagMask)); |
470 __ j(NOT_ZERO, deopt); | 502 __ j(NOT_ZERO, deopt); |
471 | 503 |
472 Condition true_condition = TokenKindToSmiCondition(comp->kind()); | 504 Condition true_condition = TokenKindToSmiCondition(comp->kind()); |
473 __ cmpl(left, right); | 505 __ cmpl(left, right); |
474 | 506 |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
510 Label* deopt = compiler->AddDeoptStub(comp->cid(), | 542 Label* deopt = compiler->AddDeoptStub(comp->cid(), |
511 comp->token_pos(), | 543 comp->token_pos(), |
512 comp->try_index(), | 544 comp->try_index(), |
513 kDeoptDoubleComparison, | 545 kDeoptDoubleComparison, |
514 left, | 546 left, |
515 right); | 547 right); |
516 compiler->LoadDoubleOrSmiToXmm(XMM0, left, temp, deopt); | 548 compiler->LoadDoubleOrSmiToXmm(XMM0, left, temp, deopt); |
517 compiler->LoadDoubleOrSmiToXmm(XMM1, right, temp, deopt); | 549 compiler->LoadDoubleOrSmiToXmm(XMM1, right, temp, deopt); |
518 | 550 |
519 Condition true_condition = TokenKindToDoubleCondition(comp->kind()); | 551 Condition true_condition = TokenKindToDoubleCondition(comp->kind()); |
520 __ comisd(XMM0, XMM1); | |
521 | |
522 if (comp->is_fused_with_branch()) { | 552 if (comp->is_fused_with_branch()) { |
523 BranchInstr* branch = comp->fused_with_branch(); | 553 compiler->EmitDoubleCompareBranch( |
524 BlockEntryInstr* nan_result = branch->is_negated() ? | 554 true_condition, XMM0, XMM1, comp->fused_with_branch()); |
525 branch->true_successor() : branch->false_successor(); | |
526 __ j(PARITY_EVEN, compiler->GetBlockLabel(nan_result)); | |
527 branch->EmitBranchOnCondition(compiler, true_condition); | |
528 } else { | 555 } else { |
529 Register result = comp->locs()->out().reg(); | 556 compiler->EmitDoubleCompareBool( |
530 Label is_false, is_true, done; | 557 true_condition, XMM0, XMM1, comp->locs()->out().reg()); |
531 __ j(PARITY_EVEN, &is_false, Assembler::kNearJump); // NaN -> false; | |
532 __ j(true_condition, &is_true, Assembler::kNearJump); | |
533 __ Bind(&is_false); | |
534 __ LoadObject(result, compiler->bool_false()); | |
535 __ jmp(&done); | |
536 __ Bind(&is_true); | |
537 __ LoadObject(result, compiler->bool_true()); | |
538 __ Bind(&done); | |
539 } | 558 } |
540 } | 559 } |
541 | 560 |
542 | 561 |
543 void RelationalOpComp::EmitNativeCode(FlowGraphCompiler* compiler) { | 562 void RelationalOpComp::EmitNativeCode(FlowGraphCompiler* compiler) { |
544 if (operands_class_id() == kSmi) { | 563 if (operands_class_id() == kSmi) { |
545 EmitSmiRelationalOp(compiler, this); | 564 EmitSmiRelationalOp(compiler, this); |
546 return; | 565 return; |
547 } | 566 } |
548 if (operands_class_id() == kDouble) { | 567 if (operands_class_id() == kDouble) { |
(...skipping 1405 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1954 instance_call()->argument_names()); | 1973 instance_call()->argument_names()); |
1955 } | 1974 } |
1956 __ Bind(&done); | 1975 __ Bind(&done); |
1957 } | 1976 } |
1958 | 1977 |
1959 } // namespace dart | 1978 } // namespace dart |
1960 | 1979 |
1961 #undef __ | 1980 #undef __ |
1962 | 1981 |
1963 #endif // defined TARGET_ARCH_X64 | 1982 #endif // defined TARGET_ARCH_X64 |
OLD | NEW |