Mercurial > hg > graal-compiler
comparison src/cpu/x86/vm/assembler_x86.cpp @ 986:62001a362ce9
6827605: new String intrinsics may prevent EA scalar replacement
6875866: Intrinsic for String.indexOf() is broken on x86 with SSE4.2
Summary: Modify String intrinsic methods to pass char[] pointers instead of string oops.
Reviewed-by: never
author | kvn |
---|---|
date | Mon, 14 Sep 2009 12:14:20 -0700 |
parents | 60fea60a6db5 |
children | d40f03b57795 |
comparison
equal
deleted
inserted
replaced
985:685e959d09ea | 986:62001a362ce9 |
---|---|
8402 movptr(r12_heapbase, ExternalAddress((address)Universe::narrow_oop_base_addr())); | 8402 movptr(r12_heapbase, ExternalAddress((address)Universe::narrow_oop_base_addr())); |
8403 } | 8403 } |
8404 } | 8404 } |
8405 #endif // _LP64 | 8405 #endif // _LP64 |
8406 | 8406 |
8407 // IndexOf substring. | |
8408 void MacroAssembler::string_indexof(Register str1, Register str2, | |
8409 Register cnt1, Register cnt2, Register result, | |
8410 XMMRegister vec, Register tmp) { | |
8411 assert(UseSSE42Intrinsics, "SSE4.2 is required"); | |
8412 | |
8413 Label RELOAD_SUBSTR, PREP_FOR_SCAN, SCAN_TO_SUBSTR, | |
8414 SCAN_SUBSTR, RET_NOT_FOUND, CLEANUP; | |
8415 | |
8416 push(str1); // string addr | |
8417 push(str2); // substr addr | |
8418 push(cnt2); // substr count | |
8419 jmpb(PREP_FOR_SCAN); | |
8420 | |
8421 // Substr count saved at sp | |
8422 // Substr saved at sp+1*wordSize | |
8423 // String saved at sp+2*wordSize | |
8424 | |
8425 // Reload substr for rescan | |
8426 bind(RELOAD_SUBSTR); | |
8427 movl(cnt2, Address(rsp, 0)); | |
8428 movptr(str2, Address(rsp, wordSize)); | |
8429 // We came here after the beginninig of the substring was | |
8430 // matched but the rest of it was not so we need to search | |
8431 // again. Start from the next element after the previous match. | |
8432 subptr(str1, result); // Restore counter | |
8433 shrl(str1, 1); | |
8434 addl(cnt1, str1); | |
8435 lea(str1, Address(result, 2)); // Reload string | |
8436 | |
8437 // Load substr | |
8438 bind(PREP_FOR_SCAN); | |
8439 movdqu(vec, Address(str2, 0)); | |
8440 addl(cnt1, 8); // prime the loop | |
8441 subptr(str1, 16); | |
8442 | |
8443 // Scan string for substr in 16-byte vectors | |
8444 bind(SCAN_TO_SUBSTR); | |
8445 subl(cnt1, 8); | |
8446 addptr(str1, 16); | |
8447 | |
8448 // pcmpestri | |
8449 // inputs: | |
8450 // xmm - substring | |
8451 // rax - substring length (elements count) | |
8452 // mem - scaned string | |
8453 // rdx - string length (elements count) | |
8454 // 0xd - mode: 1100 (substring search) + 01 (unsigned shorts) | |
8455 // outputs: | |
8456 // rcx - matched index in string | |
8457 assert(cnt1 == rdx && cnt2 == rax && tmp == rcx, "pcmpestri"); | |
8458 | |
8459 pcmpestri(vec, Address(str1, 0), 0x0d); | |
8460 jcc(Assembler::above, SCAN_TO_SUBSTR); // CF == 0 && ZF == 0 | |
8461 jccb(Assembler::aboveEqual, RET_NOT_FOUND); // CF == 0 | |
8462 | |
8463 // Fallthrough: found a potential substr | |
8464 | |
8465 // Make sure string is still long enough | |
8466 subl(cnt1, tmp); | |
8467 cmpl(cnt1, cnt2); | |
8468 jccb(Assembler::negative, RET_NOT_FOUND); | |
8469 // Compute start addr of substr | |
8470 lea(str1, Address(str1, tmp, Address::times_2)); | |
8471 movptr(result, str1); // save | |
8472 | |
8473 // Compare potential substr | |
8474 addl(cnt1, 8); // prime the loop | |
8475 addl(cnt2, 8); | |
8476 subptr(str1, 16); | |
8477 subptr(str2, 16); | |
8478 | |
8479 // Scan 16-byte vectors of string and substr | |
8480 bind(SCAN_SUBSTR); | |
8481 subl(cnt1, 8); | |
8482 subl(cnt2, 8); | |
8483 addptr(str1, 16); | |
8484 addptr(str2, 16); | |
8485 movdqu(vec, Address(str2, 0)); | |
8486 pcmpestri(vec, Address(str1, 0), 0x0d); | |
8487 jcc(Assembler::noOverflow, RELOAD_SUBSTR); // OF == 0 | |
8488 jcc(Assembler::positive, SCAN_SUBSTR); // SF == 0 | |
8489 | |
8490 // Compute substr offset | |
8491 subptr(result, Address(rsp, 2*wordSize)); | |
8492 shrl(result, 1); // index | |
8493 jmpb(CLEANUP); | |
8494 | |
8495 bind(RET_NOT_FOUND); | |
8496 movl(result, -1); | |
8497 | |
8498 bind(CLEANUP); | |
8499 addptr(rsp, 3*wordSize); | |
8500 } | |
8501 | |
8502 // Compare strings. | |
8503 void MacroAssembler::string_compare(Register str1, Register str2, | |
8504 Register cnt1, Register cnt2, Register result, | |
8505 XMMRegister vec1, XMMRegister vec2) { | |
8506 Label LENGTH_DIFF_LABEL, POP_LABEL, DONE_LABEL, WHILE_HEAD_LABEL; | |
8507 | |
8508 // Compute the minimum of the string lengths and the | |
8509 // difference of the string lengths (stack). | |
8510 // Do the conditional move stuff | |
8511 movl(result, cnt1); | |
8512 subl(cnt1, cnt2); | |
8513 push(cnt1); | |
8514 if (VM_Version::supports_cmov()) { | |
8515 cmovl(Assembler::lessEqual, cnt2, result); | |
8516 } else { | |
8517 Label GT_LABEL; | |
8518 jccb(Assembler::greater, GT_LABEL); | |
8519 movl(cnt2, result); | |
8520 bind(GT_LABEL); | |
8521 } | |
8522 | |
8523 // Is the minimum length zero? | |
8524 testl(cnt2, cnt2); | |
8525 jcc(Assembler::zero, LENGTH_DIFF_LABEL); | |
8526 | |
8527 // Load first characters | |
8528 load_unsigned_short(result, Address(str1, 0)); | |
8529 load_unsigned_short(cnt1, Address(str2, 0)); | |
8530 | |
8531 // Compare first characters | |
8532 subl(result, cnt1); | |
8533 jcc(Assembler::notZero, POP_LABEL); | |
8534 decrementl(cnt2); | |
8535 jcc(Assembler::zero, LENGTH_DIFF_LABEL); | |
8536 | |
8537 { | |
8538 // Check after comparing first character to see if strings are equivalent | |
8539 Label LSkip2; | |
8540 // Check if the strings start at same location | |
8541 cmpptr(str1, str2); | |
8542 jccb(Assembler::notEqual, LSkip2); | |
8543 | |
8544 // Check if the length difference is zero (from stack) | |
8545 cmpl(Address(rsp, 0), 0x0); | |
8546 jcc(Assembler::equal, LENGTH_DIFF_LABEL); | |
8547 | |
8548 // Strings might not be equivalent | |
8549 bind(LSkip2); | |
8550 } | |
8551 | |
8552 // Advance to next character | |
8553 addptr(str1, 2); | |
8554 addptr(str2, 2); | |
8555 | |
8556 if (UseSSE42Intrinsics) { | |
8557 // With SSE4.2, use double quad vector compare | |
8558 Label COMPARE_VECTORS, VECTOR_NOT_EQUAL, COMPARE_TAIL; | |
8559 // Setup to compare 16-byte vectors | |
8560 movl(cnt1, cnt2); | |
8561 andl(cnt2, 0xfffffff8); // cnt2 holds the vector count | |
8562 andl(cnt1, 0x00000007); // cnt1 holds the tail count | |
8563 testl(cnt2, cnt2); | |
8564 jccb(Assembler::zero, COMPARE_TAIL); | |
8565 | |
8566 lea(str2, Address(str2, cnt2, Address::times_2)); | |
8567 lea(str1, Address(str1, cnt2, Address::times_2)); | |
8568 negptr(cnt2); | |
8569 | |
8570 bind(COMPARE_VECTORS); | |
8571 movdqu(vec1, Address(str1, cnt2, Address::times_2)); | |
8572 movdqu(vec2, Address(str2, cnt2, Address::times_2)); | |
8573 pxor(vec1, vec2); | |
8574 ptest(vec1, vec1); | |
8575 jccb(Assembler::notZero, VECTOR_NOT_EQUAL); | |
8576 addptr(cnt2, 8); | |
8577 jcc(Assembler::notZero, COMPARE_VECTORS); | |
8578 jmpb(COMPARE_TAIL); | |
8579 | |
8580 // Mismatched characters in the vectors | |
8581 bind(VECTOR_NOT_EQUAL); | |
8582 lea(str1, Address(str1, cnt2, Address::times_2)); | |
8583 lea(str2, Address(str2, cnt2, Address::times_2)); | |
8584 movl(cnt1, 8); | |
8585 | |
8586 // Compare tail (< 8 chars), or rescan last vectors to | |
8587 // find 1st mismatched characters | |
8588 bind(COMPARE_TAIL); | |
8589 testl(cnt1, cnt1); | |
8590 jccb(Assembler::zero, LENGTH_DIFF_LABEL); | |
8591 movl(cnt2, cnt1); | |
8592 // Fallthru to tail compare | |
8593 } | |
8594 | |
8595 // Shift str2 and str1 to the end of the arrays, negate min | |
8596 lea(str1, Address(str1, cnt2, Address::times_2, 0)); | |
8597 lea(str2, Address(str2, cnt2, Address::times_2, 0)); | |
8598 negptr(cnt2); | |
8599 | |
8600 // Compare the rest of the characters | |
8601 bind(WHILE_HEAD_LABEL); | |
8602 load_unsigned_short(result, Address(str1, cnt2, Address::times_2, 0)); | |
8603 load_unsigned_short(cnt1, Address(str2, cnt2, Address::times_2, 0)); | |
8604 subl(result, cnt1); | |
8605 jccb(Assembler::notZero, POP_LABEL); | |
8606 increment(cnt2); | |
8607 jcc(Assembler::notZero, WHILE_HEAD_LABEL); | |
8608 | |
8609 // Strings are equal up to min length. Return the length difference. | |
8610 bind(LENGTH_DIFF_LABEL); | |
8611 pop(result); | |
8612 jmpb(DONE_LABEL); | |
8613 | |
8614 // Discard the stored length difference | |
8615 bind(POP_LABEL); | |
8616 addptr(rsp, wordSize); | |
8617 | |
8618 // That's it | |
8619 bind(DONE_LABEL); | |
8620 } | |
8621 | |
8622 // Compare char[] arrays aligned to 4 bytes or substrings. | |
8623 void MacroAssembler::char_arrays_equals(bool is_array_equ, Register ary1, Register ary2, | |
8624 Register limit, Register result, Register chr, | |
8625 XMMRegister vec1, XMMRegister vec2) { | |
8626 Label TRUE_LABEL, FALSE_LABEL, DONE, COMPARE_VECTORS, COMPARE_CHAR; | |
8627 | |
8628 int length_offset = arrayOopDesc::length_offset_in_bytes(); | |
8629 int base_offset = arrayOopDesc::base_offset_in_bytes(T_CHAR); | |
8630 | |
8631 // Check the input args | |
8632 cmpptr(ary1, ary2); | |
8633 jcc(Assembler::equal, TRUE_LABEL); | |
8634 | |
8635 if (is_array_equ) { | |
8636 // Need additional checks for arrays_equals. | |
8637 andptr(ary1, ary2); | |
8638 jcc(Assembler::zero, FALSE_LABEL); // One pointer is NULL | |
8639 | |
8640 // Check the lengths | |
8641 movl(limit, Address(ary1, length_offset)); | |
8642 cmpl(limit, Address(ary2, length_offset)); | |
8643 jcc(Assembler::notEqual, FALSE_LABEL); | |
8644 } | |
8645 | |
8646 // count == 0 | |
8647 testl(limit, limit); | |
8648 jcc(Assembler::zero, TRUE_LABEL); | |
8649 | |
8650 if (is_array_equ) { | |
8651 // Load array address | |
8652 lea(ary1, Address(ary1, base_offset)); | |
8653 lea(ary2, Address(ary2, base_offset)); | |
8654 } | |
8655 | |
8656 shll(limit, 1); // byte count != 0 | |
8657 movl(result, limit); // copy | |
8658 | |
8659 if (UseSSE42Intrinsics) { | |
8660 // With SSE4.2, use double quad vector compare | |
8661 Label COMPARE_WIDE_VECTORS, COMPARE_TAIL; | |
8662 // Compare 16-byte vectors | |
8663 andl(result, 0x0000000e); // tail count (in bytes) | |
8664 andl(limit, 0xfffffff0); // vector count (in bytes) | |
8665 jccb(Assembler::zero, COMPARE_TAIL); | |
8666 | |
8667 lea(ary1, Address(ary1, limit, Address::times_1)); | |
8668 lea(ary2, Address(ary2, limit, Address::times_1)); | |
8669 negptr(limit); | |
8670 | |
8671 bind(COMPARE_WIDE_VECTORS); | |
8672 movdqu(vec1, Address(ary1, limit, Address::times_1)); | |
8673 movdqu(vec2, Address(ary2, limit, Address::times_1)); | |
8674 pxor(vec1, vec2); | |
8675 ptest(vec1, vec1); | |
8676 jccb(Assembler::notZero, FALSE_LABEL); | |
8677 addptr(limit, 16); | |
8678 jcc(Assembler::notZero, COMPARE_WIDE_VECTORS); | |
8679 | |
8680 bind(COMPARE_TAIL); // limit is zero | |
8681 movl(limit, result); | |
8682 // Fallthru to tail compare | |
8683 } | |
8684 | |
8685 // Compare 4-byte vectors | |
8686 andl(limit, 0xfffffffc); // vector count (in bytes) | |
8687 jccb(Assembler::zero, COMPARE_CHAR); | |
8688 | |
8689 lea(ary1, Address(ary1, limit, Address::times_1)); | |
8690 lea(ary2, Address(ary2, limit, Address::times_1)); | |
8691 negptr(limit); | |
8692 | |
8693 bind(COMPARE_VECTORS); | |
8694 movl(chr, Address(ary1, limit, Address::times_1)); | |
8695 cmpl(chr, Address(ary2, limit, Address::times_1)); | |
8696 jccb(Assembler::notEqual, FALSE_LABEL); | |
8697 addptr(limit, 4); | |
8698 jcc(Assembler::notZero, COMPARE_VECTORS); | |
8699 | |
8700 // Compare trailing char (final 2 bytes), if any | |
8701 bind(COMPARE_CHAR); | |
8702 testl(result, 0x2); // tail char | |
8703 jccb(Assembler::zero, TRUE_LABEL); | |
8704 load_unsigned_short(chr, Address(ary1, 0)); | |
8705 load_unsigned_short(limit, Address(ary2, 0)); | |
8706 cmpl(chr, limit); | |
8707 jccb(Assembler::notEqual, FALSE_LABEL); | |
8708 | |
8709 bind(TRUE_LABEL); | |
8710 movl(result, 1); // return true | |
8711 jmpb(DONE); | |
8712 | |
8713 bind(FALSE_LABEL); | |
8714 xorl(result, result); // return false | |
8715 | |
8716 // That's it | |
8717 bind(DONE); | |
8718 } | |
8719 | |
8407 Assembler::Condition MacroAssembler::negate_condition(Assembler::Condition cond) { | 8720 Assembler::Condition MacroAssembler::negate_condition(Assembler::Condition cond) { |
8408 switch (cond) { | 8721 switch (cond) { |
8409 // Note some conditions are synonyms for others | 8722 // Note some conditions are synonyms for others |
8410 case Assembler::zero: return Assembler::notZero; | 8723 case Assembler::zero: return Assembler::notZero; |
8411 case Assembler::notZero: return Assembler::zero; | 8724 case Assembler::notZero: return Assembler::zero; |