mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-24 04:54:40 +02:00
8149655: PPC64: Implement CompactString intrinsics
Reviewed-by: goetz, kvn
This commit is contained in:
parent
a026f88a38
commit
de01af89d8
8 changed files with 1261 additions and 43 deletions
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2015 SAP SE. All rights reserved.
|
||||
* Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2016 SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -75,8 +75,7 @@ define_pd_global(size_t, CMSYoungGenPerWorker, 16*M); // Default max size of CM
|
|||
|
||||
define_pd_global(uintx, TypeProfileLevel, 111);
|
||||
|
||||
// No performance work done here yet.
|
||||
define_pd_global(bool, CompactStrings, false);
|
||||
define_pd_global(bool, CompactStrings, true);
|
||||
|
||||
// Platform dependent flag handling: flags only defined on this platform.
|
||||
#define ARCH_FLAGS(develop, product, diagnostic, experimental, notproduct, range, constraint) \
|
||||
|
|
|
@ -45,6 +45,9 @@
|
|||
#include "gc/g1/g1SATBCardTableModRefBS.hpp"
|
||||
#include "gc/g1/heapRegion.hpp"
|
||||
#endif // INCLUDE_ALL_GCS
|
||||
#ifdef COMPILER2
|
||||
#include "opto/intrinsicnode.hpp"
|
||||
#endif
|
||||
|
||||
#ifdef PRODUCT
|
||||
#define BLOCK_COMMENT(str) // nothing
|
||||
|
@ -3168,6 +3171,553 @@ void MacroAssembler::clear_memory_doubleword(Register base_ptr, Register cnt_dwo
|
|||
|
||||
/////////////////////////////////////////// String intrinsics ////////////////////////////////////////////
|
||||
|
||||
#ifdef COMPILER2
|
||||
// Intrinsics for CompactStrings
|
||||
|
||||
// Compress char[] to byte[] by compressing 16 bytes at once.
|
||||
void MacroAssembler::string_compress_16(Register src, Register dst, Register cnt,
|
||||
Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5,
|
||||
Label& Lfailure) {
|
||||
|
||||
const Register tmp0 = R0;
|
||||
assert_different_registers(src, dst, cnt, tmp0, tmp1, tmp2, tmp3, tmp4, tmp5);
|
||||
Label Lloop, Lslow;
|
||||
|
||||
// Check if cnt >= 8 (= 16 bytes)
|
||||
lis(tmp1, 0xFF); // tmp1 = 0x00FF00FF00FF00FF
|
||||
srwi_(tmp2, cnt, 3);
|
||||
beq(CCR0, Lslow);
|
||||
ori(tmp1, tmp1, 0xFF);
|
||||
rldimi(tmp1, tmp1, 32, 0);
|
||||
mtctr(tmp2);
|
||||
|
||||
// 2x unrolled loop
|
||||
bind(Lloop);
|
||||
ld(tmp2, 0, src); // _0_1_2_3 (Big Endian)
|
||||
ld(tmp4, 8, src); // _4_5_6_7
|
||||
|
||||
orr(tmp0, tmp2, tmp4);
|
||||
rldicl(tmp3, tmp2, 6*8, 64-24); // _____1_2
|
||||
rldimi(tmp2, tmp2, 2*8, 2*8); // _0_2_3_3
|
||||
rldicl(tmp5, tmp4, 6*8, 64-24); // _____5_6
|
||||
rldimi(tmp4, tmp4, 2*8, 2*8); // _4_6_7_7
|
||||
|
||||
andc_(tmp0, tmp0, tmp1);
|
||||
bne(CCR0, Lfailure); // Not latin1.
|
||||
addi(src, src, 16);
|
||||
|
||||
rlwimi(tmp3, tmp2, 0*8, 24, 31);// _____1_3
|
||||
srdi(tmp2, tmp2, 3*8); // ____0_2_
|
||||
rlwimi(tmp5, tmp4, 0*8, 24, 31);// _____5_7
|
||||
srdi(tmp4, tmp4, 3*8); // ____4_6_
|
||||
|
||||
orr(tmp2, tmp2, tmp3); // ____0123
|
||||
orr(tmp4, tmp4, tmp5); // ____4567
|
||||
|
||||
stw(tmp2, 0, dst);
|
||||
stw(tmp4, 4, dst);
|
||||
addi(dst, dst, 8);
|
||||
bdnz(Lloop);
|
||||
|
||||
bind(Lslow); // Fallback to slow version
|
||||
}
|
||||
|
||||
// Compress char[] to byte[]. cnt must be positive int.
|
||||
void MacroAssembler::string_compress(Register src, Register dst, Register cnt, Register tmp, Label& Lfailure) {
|
||||
Label Lloop;
|
||||
mtctr(cnt);
|
||||
|
||||
bind(Lloop);
|
||||
lhz(tmp, 0, src);
|
||||
cmplwi(CCR0, tmp, 0xff);
|
||||
bgt(CCR0, Lfailure); // Not latin1.
|
||||
addi(src, src, 2);
|
||||
stb(tmp, 0, dst);
|
||||
addi(dst, dst, 1);
|
||||
bdnz(Lloop);
|
||||
}
|
||||
|
||||
// Inflate byte[] to char[] by inflating 16 bytes at once.
|
||||
void MacroAssembler::string_inflate_16(Register src, Register dst, Register cnt,
|
||||
Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5) {
|
||||
const Register tmp0 = R0;
|
||||
assert_different_registers(src, dst, cnt, tmp0, tmp1, tmp2, tmp3, tmp4, tmp5);
|
||||
Label Lloop, Lslow;
|
||||
|
||||
// Check if cnt >= 8
|
||||
srwi_(tmp2, cnt, 3);
|
||||
beq(CCR0, Lslow);
|
||||
lis(tmp1, 0xFF); // tmp1 = 0x00FF00FF
|
||||
ori(tmp1, tmp1, 0xFF);
|
||||
mtctr(tmp2);
|
||||
|
||||
// 2x unrolled loop
|
||||
bind(Lloop);
|
||||
lwz(tmp2, 0, src); // ____0123 (Big Endian)
|
||||
lwz(tmp4, 4, src); // ____4567
|
||||
addi(src, src, 8);
|
||||
|
||||
rldicl(tmp3, tmp2, 7*8, 64-8); // _______2
|
||||
rlwimi(tmp2, tmp2, 3*8, 16, 23);// ____0113
|
||||
rldicl(tmp5, tmp4, 7*8, 64-8); // _______6
|
||||
rlwimi(tmp4, tmp4, 3*8, 16, 23);// ____4557
|
||||
|
||||
andc(tmp0, tmp2, tmp1); // ____0_1_
|
||||
rlwimi(tmp2, tmp3, 2*8, 0, 23); // _____2_3
|
||||
andc(tmp3, tmp4, tmp1); // ____4_5_
|
||||
rlwimi(tmp4, tmp5, 2*8, 0, 23); // _____6_7
|
||||
|
||||
rldimi(tmp2, tmp0, 3*8, 0*8); // _0_1_2_3
|
||||
rldimi(tmp4, tmp3, 3*8, 0*8); // _4_5_6_7
|
||||
|
||||
std(tmp2, 0, dst);
|
||||
std(tmp4, 8, dst);
|
||||
addi(dst, dst, 16);
|
||||
bdnz(Lloop);
|
||||
|
||||
bind(Lslow); // Fallback to slow version
|
||||
}
|
||||
|
||||
// Inflate byte[] to char[]. cnt must be positive int.
|
||||
void MacroAssembler::string_inflate(Register src, Register dst, Register cnt, Register tmp) {
|
||||
Label Lloop;
|
||||
mtctr(cnt);
|
||||
|
||||
bind(Lloop);
|
||||
lbz(tmp, 0, src);
|
||||
addi(src, src, 1);
|
||||
sth(tmp, 0, dst);
|
||||
addi(dst, dst, 2);
|
||||
bdnz(Lloop);
|
||||
}
|
||||
|
||||
void MacroAssembler::string_compare(Register str1, Register str2,
|
||||
Register cnt1, Register cnt2,
|
||||
Register tmp1, Register result, int ae) {
|
||||
const Register tmp0 = R0,
|
||||
diff = tmp1;
|
||||
|
||||
assert_different_registers(str1, str2, cnt1, cnt2, tmp0, tmp1, result);
|
||||
Label Ldone, Lslow, Lloop, Lreturn_diff;
|
||||
|
||||
// Note: Making use of the fact that compareTo(a, b) == -compareTo(b, a)
|
||||
// we interchange str1 and str2 in the UL case and negate the result.
|
||||
// Like this, str1 is always latin1 encoded, except for the UU case.
|
||||
// In addition, we need 0 (or sign which is 0) extend.
|
||||
|
||||
if (ae == StrIntrinsicNode::UU) {
|
||||
srwi(cnt1, cnt1, 1);
|
||||
} else {
|
||||
clrldi(cnt1, cnt1, 32);
|
||||
}
|
||||
|
||||
if (ae != StrIntrinsicNode::LL) {
|
||||
srwi(cnt2, cnt2, 1);
|
||||
} else {
|
||||
clrldi(cnt2, cnt2, 32);
|
||||
}
|
||||
|
||||
// See if the lengths are different, and calculate min in cnt1.
|
||||
// Save diff in case we need it for a tie-breaker.
|
||||
subf_(diff, cnt2, cnt1); // diff = cnt1 - cnt2
|
||||
// if (diff > 0) { cnt1 = cnt2; }
|
||||
if (VM_Version::has_isel()) {
|
||||
isel(cnt1, CCR0, Assembler::greater, /*invert*/ false, cnt2);
|
||||
} else {
|
||||
Label Lskip;
|
||||
blt(CCR0, Lskip);
|
||||
mr(cnt1, cnt2);
|
||||
bind(Lskip);
|
||||
}
|
||||
|
||||
// Rename registers
|
||||
Register chr1 = result;
|
||||
Register chr2 = tmp0;
|
||||
|
||||
// Compare multiple characters in fast loop (only implemented for same encoding).
|
||||
int stride1 = 8, stride2 = 8;
|
||||
if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) {
|
||||
int log2_chars_per_iter = (ae == StrIntrinsicNode::LL) ? 3 : 2;
|
||||
Label Lfastloop, Lskipfast;
|
||||
|
||||
srwi_(tmp0, cnt1, log2_chars_per_iter);
|
||||
beq(CCR0, Lskipfast);
|
||||
rldicl(cnt2, cnt1, 0, 64 - log2_chars_per_iter); // Remaining characters.
|
||||
li(cnt1, 1 << log2_chars_per_iter); // Initialize for failure case: Rescan characters from current iteration.
|
||||
mtctr(tmp0);
|
||||
|
||||
bind(Lfastloop);
|
||||
ld(chr1, 0, str1);
|
||||
ld(chr2, 0, str2);
|
||||
cmpd(CCR0, chr1, chr2);
|
||||
bne(CCR0, Lslow);
|
||||
addi(str1, str1, stride1);
|
||||
addi(str2, str2, stride2);
|
||||
bdnz(Lfastloop);
|
||||
mr(cnt1, cnt2); // Remaining characters.
|
||||
bind(Lskipfast);
|
||||
}
|
||||
|
||||
// Loop which searches the first difference character by character.
|
||||
cmpwi(CCR0, cnt1, 0);
|
||||
beq(CCR0, Lreturn_diff);
|
||||
bind(Lslow);
|
||||
mtctr(cnt1);
|
||||
|
||||
switch (ae) {
|
||||
case StrIntrinsicNode::LL: stride1 = 1; stride2 = 1; break;
|
||||
case StrIntrinsicNode::UL: // fallthru (see comment above)
|
||||
case StrIntrinsicNode::LU: stride1 = 1; stride2 = 2; break;
|
||||
case StrIntrinsicNode::UU: stride1 = 2; stride2 = 2; break;
|
||||
default: ShouldNotReachHere(); break;
|
||||
}
|
||||
|
||||
bind(Lloop);
|
||||
if (stride1 == 1) { lbz(chr1, 0, str1); } else { lhz(chr1, 0, str1); }
|
||||
if (stride2 == 1) { lbz(chr2, 0, str2); } else { lhz(chr2, 0, str2); }
|
||||
subf_(result, chr2, chr1); // result = chr1 - chr2
|
||||
bne(CCR0, Ldone);
|
||||
addi(str1, str1, stride1);
|
||||
addi(str2, str2, stride2);
|
||||
bdnz(Lloop);
|
||||
|
||||
// If strings are equal up to min length, return the length difference.
|
||||
bind(Lreturn_diff);
|
||||
mr(result, diff);
|
||||
|
||||
// Otherwise, return the difference between the first mismatched chars.
|
||||
bind(Ldone);
|
||||
if (ae == StrIntrinsicNode::UL) {
|
||||
neg(result, result); // Negate result (see note above).
|
||||
}
|
||||
}
|
||||
|
||||
void MacroAssembler::array_equals(bool is_array_equ, Register ary1, Register ary2,
|
||||
Register limit, Register tmp1, Register result, bool is_byte) {
|
||||
const Register tmp0 = R0;
|
||||
assert_different_registers(ary1, ary2, limit, tmp0, tmp1, result);
|
||||
Label Ldone, Lskiploop, Lloop, Lfastloop, Lskipfast;
|
||||
bool limit_needs_shift = false;
|
||||
|
||||
if (is_array_equ) {
|
||||
const int length_offset = arrayOopDesc::length_offset_in_bytes();
|
||||
const int base_offset = arrayOopDesc::base_offset_in_bytes(is_byte ? T_BYTE : T_CHAR);
|
||||
|
||||
// Return true if the same array.
|
||||
cmpd(CCR0, ary1, ary2);
|
||||
beq(CCR0, Lskiploop);
|
||||
|
||||
// Return false if one of them is NULL.
|
||||
cmpdi(CCR0, ary1, 0);
|
||||
cmpdi(CCR1, ary2, 0);
|
||||
li(result, 0);
|
||||
cror(CCR0, Assembler::equal, CCR1, Assembler::equal);
|
||||
beq(CCR0, Ldone);
|
||||
|
||||
// Load the lengths of arrays.
|
||||
lwz(limit, length_offset, ary1);
|
||||
lwz(tmp0, length_offset, ary2);
|
||||
|
||||
// Return false if the two arrays are not equal length.
|
||||
cmpw(CCR0, limit, tmp0);
|
||||
bne(CCR0, Ldone);
|
||||
|
||||
// Load array addresses.
|
||||
addi(ary1, ary1, base_offset);
|
||||
addi(ary2, ary2, base_offset);
|
||||
} else {
|
||||
limit_needs_shift = !is_byte;
|
||||
li(result, 0); // Assume not equal.
|
||||
}
|
||||
|
||||
// Rename registers
|
||||
Register chr1 = tmp0;
|
||||
Register chr2 = tmp1;
|
||||
|
||||
// Compare 8 bytes per iteration in fast loop.
|
||||
const int log2_chars_per_iter = is_byte ? 3 : 2;
|
||||
|
||||
srwi_(tmp0, limit, log2_chars_per_iter + (limit_needs_shift ? 1 : 0));
|
||||
beq(CCR0, Lskipfast);
|
||||
mtctr(tmp0);
|
||||
|
||||
bind(Lfastloop);
|
||||
ld(chr1, 0, ary1);
|
||||
ld(chr2, 0, ary2);
|
||||
addi(ary1, ary1, 8);
|
||||
addi(ary2, ary2, 8);
|
||||
cmpd(CCR0, chr1, chr2);
|
||||
bne(CCR0, Ldone);
|
||||
bdnz(Lfastloop);
|
||||
|
||||
bind(Lskipfast);
|
||||
rldicl_(limit, limit, limit_needs_shift ? 64 - 1 : 0, 64 - log2_chars_per_iter); // Remaining characters.
|
||||
beq(CCR0, Lskiploop);
|
||||
mtctr(limit);
|
||||
|
||||
// Character by character.
|
||||
bind(Lloop);
|
||||
if (is_byte) {
|
||||
lbz(chr1, 0, ary1);
|
||||
lbz(chr2, 0, ary2);
|
||||
addi(ary1, ary1, 1);
|
||||
addi(ary2, ary2, 1);
|
||||
} else {
|
||||
lhz(chr1, 0, ary1);
|
||||
lhz(chr2, 0, ary2);
|
||||
addi(ary1, ary1, 2);
|
||||
addi(ary2, ary2, 2);
|
||||
}
|
||||
cmpw(CCR0, chr1, chr2);
|
||||
bne(CCR0, Ldone);
|
||||
bdnz(Lloop);
|
||||
|
||||
bind(Lskiploop);
|
||||
li(result, 1); // All characters are equal.
|
||||
bind(Ldone);
|
||||
}
|
||||
|
||||
void MacroAssembler::string_indexof(Register result, Register haystack, Register haycnt,
|
||||
Register needle, ciTypeArray* needle_values, Register needlecnt, int needlecntval,
|
||||
Register tmp1, Register tmp2, Register tmp3, Register tmp4, int ae) {
|
||||
|
||||
// Ensure 0<needlecnt<=haycnt in ideal graph as prerequisite!
|
||||
Label L_TooShort, L_Found, L_NotFound, L_End;
|
||||
Register last_addr = haycnt, // Kill haycnt at the beginning.
|
||||
addr = tmp1,
|
||||
n_start = tmp2,
|
||||
ch1 = tmp3,
|
||||
ch2 = R0;
|
||||
|
||||
assert(ae != StrIntrinsicNode::LU, "Invalid encoding");
|
||||
const int h_csize = (ae == StrIntrinsicNode::LL) ? 1 : 2;
|
||||
const int n_csize = (ae == StrIntrinsicNode::UU) ? 2 : 1;
|
||||
|
||||
// **************************************************************************************************
|
||||
// Prepare for main loop: optimized for needle count >=2, bail out otherwise.
|
||||
// **************************************************************************************************
|
||||
|
||||
// Compute last haystack addr to use if no match gets found.
|
||||
clrldi(haycnt, haycnt, 32); // Ensure positive int is valid as 64 bit value.
|
||||
addi(addr, haystack, -h_csize); // Accesses use pre-increment.
|
||||
if (needlecntval == 0) { // variable needlecnt
|
||||
cmpwi(CCR6, needlecnt, 2);
|
||||
clrldi(needlecnt, needlecnt, 32); // Ensure positive int is valid as 64 bit value.
|
||||
blt(CCR6, L_TooShort); // Variable needlecnt: handle short needle separately.
|
||||
}
|
||||
|
||||
if (n_csize == 2) { lwz(n_start, 0, needle); } else { lhz(n_start, 0, needle); } // Load first 2 characters of needle.
|
||||
|
||||
if (needlecntval == 0) { // variable needlecnt
|
||||
subf(ch1, needlecnt, haycnt); // Last character index to compare is haycnt-needlecnt.
|
||||
addi(needlecnt, needlecnt, -2); // Rest of needle.
|
||||
} else { // constant needlecnt
|
||||
guarantee(needlecntval != 1, "IndexOf with single-character needle must be handled separately");
|
||||
assert((needlecntval & 0x7fff) == needlecntval, "wrong immediate");
|
||||
addi(ch1, haycnt, -needlecntval); // Last character index to compare is haycnt-needlecnt.
|
||||
if (needlecntval > 3) { li(needlecnt, needlecntval - 2); } // Rest of needle.
|
||||
}
|
||||
|
||||
if (h_csize == 2) { slwi(ch1, ch1, 1); } // Scale to number of bytes.
|
||||
|
||||
if (ae ==StrIntrinsicNode::UL) {
|
||||
srwi(tmp4, n_start, 1*8); // ___0
|
||||
rlwimi(n_start, tmp4, 2*8, 0, 23); // _0_1
|
||||
}
|
||||
|
||||
add(last_addr, haystack, ch1); // Point to last address to compare (haystack+2*(haycnt-needlecnt)).
|
||||
|
||||
// Main Loop (now we have at least 2 characters).
|
||||
Label L_OuterLoop, L_InnerLoop, L_FinalCheck, L_Comp1, L_Comp2;
|
||||
bind(L_OuterLoop); // Search for 1st 2 characters.
|
||||
Register addr_diff = tmp4;
|
||||
subf(addr_diff, addr, last_addr); // Difference between already checked address and last address to check.
|
||||
addi(addr, addr, h_csize); // This is the new address we want to use for comparing.
|
||||
srdi_(ch2, addr_diff, h_csize);
|
||||
beq(CCR0, L_FinalCheck); // 2 characters left?
|
||||
mtctr(ch2); // num of characters / 2
|
||||
bind(L_InnerLoop); // Main work horse (2x unrolled search loop)
|
||||
if (h_csize == 2) { // Load 2 characters of haystack (ignore alignment).
|
||||
lwz(ch1, 0, addr);
|
||||
lwz(ch2, 2, addr);
|
||||
} else {
|
||||
lhz(ch1, 0, addr);
|
||||
lhz(ch2, 1, addr);
|
||||
}
|
||||
cmpw(CCR0, ch1, n_start); // Compare 2 characters (1 would be sufficient but try to reduce branches to CompLoop).
|
||||
cmpw(CCR1, ch2, n_start);
|
||||
beq(CCR0, L_Comp1); // Did we find the needle start?
|
||||
beq(CCR1, L_Comp2);
|
||||
addi(addr, addr, 2 * h_csize);
|
||||
bdnz(L_InnerLoop);
|
||||
bind(L_FinalCheck);
|
||||
andi_(addr_diff, addr_diff, h_csize); // Remaining characters not covered by InnerLoop: (num of characters) & 1.
|
||||
beq(CCR0, L_NotFound);
|
||||
if (h_csize == 2) { lwz(ch1, 0, addr); } else { lhz(ch1, 0, addr); } // One position left at which we have to compare.
|
||||
cmpw(CCR1, ch1, n_start);
|
||||
beq(CCR1, L_Comp1);
|
||||
bind(L_NotFound);
|
||||
li(result, -1); // not found
|
||||
b(L_End);
|
||||
|
||||
// **************************************************************************************************
|
||||
// Special Case: unfortunately, the variable needle case can be called with needlecnt<2
|
||||
// **************************************************************************************************
|
||||
if (needlecntval == 0) { // We have to handle these cases separately.
|
||||
Label L_OneCharLoop;
|
||||
bind(L_TooShort);
|
||||
mtctr(haycnt);
|
||||
if (n_csize == 2) { lhz(n_start, 0, needle); } else { lbz(n_start, 0, needle); } // First character of needle
|
||||
bind(L_OneCharLoop);
|
||||
if (h_csize == 2) { lhzu(ch1, 2, addr); } else { lbzu(ch1, 1, addr); }
|
||||
cmpw(CCR1, ch1, n_start);
|
||||
beq(CCR1, L_Found); // Did we find the one character needle?
|
||||
bdnz(L_OneCharLoop);
|
||||
li(result, -1); // Not found.
|
||||
b(L_End);
|
||||
}
|
||||
|
||||
// **************************************************************************************************
|
||||
// Regular Case Part II: compare rest of needle (first 2 characters have been compared already)
|
||||
// **************************************************************************************************
|
||||
|
||||
// Compare the rest
|
||||
bind(L_Comp2);
|
||||
addi(addr, addr, h_csize); // First comparison has failed, 2nd one hit.
|
||||
bind(L_Comp1); // Addr points to possible needle start.
|
||||
if (needlecntval != 2) { // Const needlecnt==2?
|
||||
if (needlecntval != 3) {
|
||||
if (needlecntval == 0) { beq(CCR6, L_Found); } // Variable needlecnt==2?
|
||||
Register n_ind = tmp4,
|
||||
h_ind = n_ind;
|
||||
li(n_ind, 2 * n_csize); // First 2 characters are already compared, use index 2.
|
||||
mtctr(needlecnt); // Decremented by 2, still > 0.
|
||||
Label L_CompLoop;
|
||||
bind(L_CompLoop);
|
||||
if (ae ==StrIntrinsicNode::UL) {
|
||||
h_ind = ch1;
|
||||
sldi(h_ind, n_ind, 1);
|
||||
}
|
||||
if (n_csize == 2) { lhzx(ch2, needle, n_ind); } else { lbzx(ch2, needle, n_ind); }
|
||||
if (h_csize == 2) { lhzx(ch1, addr, h_ind); } else { lbzx(ch1, addr, h_ind); }
|
||||
cmpw(CCR1, ch1, ch2);
|
||||
bne(CCR1, L_OuterLoop);
|
||||
addi(n_ind, n_ind, n_csize);
|
||||
bdnz(L_CompLoop);
|
||||
} else { // No loop required if there's only one needle character left.
|
||||
if (n_csize == 2) { lhz(ch2, 2 * 2, needle); } else { lbz(ch2, 2 * 1, needle); }
|
||||
if (h_csize == 2) { lhz(ch1, 2 * 2, addr); } else { lbz(ch1, 2 * 1, addr); }
|
||||
cmpw(CCR1, ch1, ch2);
|
||||
bne(CCR1, L_OuterLoop);
|
||||
}
|
||||
}
|
||||
// Return index ...
|
||||
bind(L_Found);
|
||||
subf(result, haystack, addr); // relative to haystack, ...
|
||||
if (h_csize == 2) { srdi(result, result, 1); } // in characters.
|
||||
bind(L_End);
|
||||
} // string_indexof
|
||||
|
||||
void MacroAssembler::string_indexof_char(Register result, Register haystack, Register haycnt,
|
||||
Register needle, jchar needleChar, Register tmp1, Register tmp2, bool is_byte) {
|
||||
assert_different_registers(haystack, haycnt, needle, tmp1, tmp2);
|
||||
|
||||
Label L_InnerLoop, L_FinalCheck, L_Found1, L_Found2, L_NotFound, L_End;
|
||||
Register addr = tmp1,
|
||||
ch1 = tmp2,
|
||||
ch2 = R0;
|
||||
|
||||
const int h_csize = is_byte ? 1 : 2;
|
||||
|
||||
//4:
|
||||
srwi_(tmp2, haycnt, 1); // Shift right by exact_log2(UNROLL_FACTOR).
|
||||
mr(addr, haystack);
|
||||
beq(CCR0, L_FinalCheck);
|
||||
mtctr(tmp2); // Move to count register.
|
||||
//8:
|
||||
bind(L_InnerLoop); // Main work horse (2x unrolled search loop).
|
||||
if (!is_byte) {
|
||||
lhz(ch1, 0, addr);
|
||||
lhz(ch2, 2, addr);
|
||||
} else {
|
||||
lbz(ch1, 0, addr);
|
||||
lbz(ch2, 1, addr);
|
||||
}
|
||||
(needle != R0) ? cmpw(CCR0, ch1, needle) : cmplwi(CCR0, ch1, (unsigned int)needleChar);
|
||||
(needle != R0) ? cmpw(CCR1, ch2, needle) : cmplwi(CCR1, ch2, (unsigned int)needleChar);
|
||||
beq(CCR0, L_Found1); // Did we find the needle?
|
||||
beq(CCR1, L_Found2);
|
||||
addi(addr, addr, 2 * h_csize);
|
||||
bdnz(L_InnerLoop);
|
||||
//16:
|
||||
bind(L_FinalCheck);
|
||||
andi_(R0, haycnt, 1);
|
||||
beq(CCR0, L_NotFound);
|
||||
if (!is_byte) { lhz(ch1, 0, addr); } else { lbz(ch1, 0, addr); } // One position left at which we have to compare.
|
||||
(needle != R0) ? cmpw(CCR1, ch1, needle) : cmplwi(CCR1, ch1, (unsigned int)needleChar);
|
||||
beq(CCR1, L_Found1);
|
||||
//21:
|
||||
bind(L_NotFound);
|
||||
li(result, -1); // Not found.
|
||||
b(L_End);
|
||||
|
||||
bind(L_Found2);
|
||||
addi(addr, addr, h_csize);
|
||||
//24:
|
||||
bind(L_Found1); // Return index ...
|
||||
subf(result, haystack, addr); // relative to haystack, ...
|
||||
if (!is_byte) { srdi(result, result, 1); } // in characters.
|
||||
bind(L_End);
|
||||
} // string_indexof_char
|
||||
|
||||
|
||||
void MacroAssembler::has_negatives(Register src, Register cnt, Register result,
|
||||
Register tmp1, Register tmp2) {
|
||||
const Register tmp0 = R0;
|
||||
assert_different_registers(src, result, cnt, tmp0, tmp1, tmp2);
|
||||
Label Lfastloop, Lslow, Lloop, Lnoneg, Ldone;
|
||||
|
||||
// Check if cnt >= 8 (= 16 bytes)
|
||||
lis(tmp1, (int)(short)0x8080); // tmp1 = 0x8080808080808080
|
||||
srwi_(tmp2, cnt, 4);
|
||||
li(result, 1); // Assume there's a negative byte.
|
||||
beq(CCR0, Lslow);
|
||||
ori(tmp1, tmp1, 0x8080);
|
||||
rldimi(tmp1, tmp1, 32, 0);
|
||||
mtctr(tmp2);
|
||||
|
||||
// 2x unrolled loop
|
||||
bind(Lfastloop);
|
||||
ld(tmp2, 0, src);
|
||||
ld(tmp0, 8, src);
|
||||
|
||||
orr(tmp0, tmp2, tmp0);
|
||||
|
||||
and_(tmp0, tmp0, tmp1);
|
||||
bne(CCR0, Ldone); // Found negative byte.
|
||||
addi(src, src, 16);
|
||||
|
||||
bdnz(Lfastloop);
|
||||
|
||||
bind(Lslow); // Fallback to slow version
|
||||
rldicl_(tmp0, cnt, 0, 64-4);
|
||||
beq(CCR0, Lnoneg);
|
||||
mtctr(tmp0);
|
||||
bind(Lloop);
|
||||
lbz(tmp0, 0, src);
|
||||
addi(src, src, 1);
|
||||
andi_(tmp0, tmp0, 0x80);
|
||||
bne(CCR0, Ldone); // Found negative byte.
|
||||
bdnz(Lloop);
|
||||
bind(Lnoneg);
|
||||
li(result, 0);
|
||||
|
||||
bind(Ldone);
|
||||
}
|
||||
|
||||
|
||||
// Intrinsics for non-CompactStrings
|
||||
|
||||
// Search for a single jchar in an jchar[].
|
||||
//
|
||||
// Assumes that result differs from all other registers.
|
||||
|
@ -3613,6 +4163,8 @@ void MacroAssembler::char_arrays_equalsImm(Register str1_reg, Register str2_reg,
|
|||
bind(Ldone_false);
|
||||
}
|
||||
|
||||
#endif // Compiler2
|
||||
|
||||
// Helpers for Intrinsic Emitters
|
||||
//
|
||||
// Revert the byte order of a 32bit value in a register
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2015 SAP SE. All rights reserved.
|
||||
* Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2016 SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -679,6 +679,39 @@ class MacroAssembler: public Assembler {
|
|||
|
||||
void clear_memory_doubleword(Register base_ptr, Register cnt_dwords, Register tmp = R0);
|
||||
|
||||
#ifdef COMPILER2
|
||||
// Intrinsics for CompactStrings
|
||||
// Compress char[] to byte[] by compressing 16 bytes at once.
|
||||
void string_compress_16(Register src, Register dst, Register cnt,
|
||||
Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5,
|
||||
Label& Lfailure);
|
||||
|
||||
// Compress char[] to byte[]. cnt must be positive int.
|
||||
void string_compress(Register src, Register dst, Register cnt, Register tmp, Label& Lfailure);
|
||||
|
||||
// Inflate byte[] to char[] by inflating 16 bytes at once.
|
||||
void string_inflate_16(Register src, Register dst, Register cnt,
|
||||
Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5);
|
||||
|
||||
// Inflate byte[] to char[]. cnt must be positive int.
|
||||
void string_inflate(Register src, Register dst, Register cnt, Register tmp);
|
||||
|
||||
void string_compare(Register str1, Register str2, Register cnt1, Register cnt2,
|
||||
Register tmp1, Register result, int ae);
|
||||
|
||||
void array_equals(bool is_array_equ, Register ary1, Register ary2,
|
||||
Register limit, Register tmp1, Register result, bool is_byte);
|
||||
|
||||
void string_indexof(Register result, Register haystack, Register haycnt,
|
||||
Register needle, ciTypeArray* needle_values, Register needlecnt, int needlecntval,
|
||||
Register tmp1, Register tmp2, Register tmp3, Register tmp4, int ae);
|
||||
|
||||
void string_indexof_char(Register result, Register haystack, Register haycnt,
|
||||
Register needle, jchar needleChar, Register tmp1, Register tmp2, bool is_byte);
|
||||
|
||||
void has_negatives(Register src, Register cnt, Register result, Register tmp1, Register tmp2);
|
||||
|
||||
// Intrinsics for non-CompactStrings
|
||||
// Needle of length 1.
|
||||
void string_indexof_1(Register result, Register haystack, Register haycnt,
|
||||
Register needle, jchar needleChar,
|
||||
|
@ -694,6 +727,7 @@ class MacroAssembler: public Assembler {
|
|||
Register tmp5_reg);
|
||||
void char_arrays_equalsImm(Register str1_reg, Register str2_reg, int cntval, Register result_reg,
|
||||
Register tmp1_reg, Register tmp2_reg);
|
||||
#endif
|
||||
|
||||
// Emitters for BigInteger.multiplyToLen intrinsic.
|
||||
inline void multiply64(Register dest_hi, Register dest_lo,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
// Copyright (c) 2012, 2015 SAP SE. All rights reserved.
|
||||
// Copyright (c) 2012, 2016 SAP SE. All rights reserved.
|
||||
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
//
|
||||
// This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -2024,13 +2024,13 @@ const bool Matcher::match_rule_supported(int opcode) {
|
|||
return (UsePopCountInstruction && VM_Version::has_popcntw());
|
||||
|
||||
case Op_StrComp:
|
||||
return SpecialStringCompareTo && !CompactStrings;
|
||||
return SpecialStringCompareTo;
|
||||
case Op_StrEquals:
|
||||
return SpecialStringEquals && !CompactStrings;
|
||||
return SpecialStringEquals;
|
||||
case Op_StrIndexOf:
|
||||
return SpecialStringIndexOf && !CompactStrings;
|
||||
return SpecialStringIndexOf;
|
||||
case Op_StrIndexOfChar:
|
||||
return SpecialStringIndexOf && !CompactStrings;
|
||||
return SpecialStringIndexOf;
|
||||
}
|
||||
|
||||
return true; // Per default match rules are supported.
|
||||
|
@ -11022,6 +11022,584 @@ instruct inlineCallClearArray(rarg1RegL cnt, rarg2RegP base, Universe dummy, reg
|
|||
ins_pipe(pipe_class_default);
|
||||
%}
|
||||
|
||||
instruct string_compareL(rarg1RegP str1, rarg2RegP str2, rarg3RegI cnt1, rarg4RegI cnt2, iRegIdst result,
|
||||
iRegIdst tmp, regCTR ctr, flagsRegCR0 cr0) %{
|
||||
predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::LL);
|
||||
match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
|
||||
effect(TEMP_DEF result, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL ctr, KILL cr0, TEMP tmp);
|
||||
ins_cost(300);
|
||||
format %{ "String Compare byte[] $str1,$cnt1,$str2,$cnt2 -> $result \t// KILL $tmp" %}
|
||||
ins_encode %{
|
||||
// TODO: PPC port $archOpcode(ppc64Opcode_compound);
|
||||
__ string_compare($str1$$Register, $str2$$Register,
|
||||
$cnt1$$Register, $cnt2$$Register,
|
||||
$tmp$$Register,
|
||||
$result$$Register, StrIntrinsicNode::LL);
|
||||
%}
|
||||
ins_pipe(pipe_class_default);
|
||||
%}
|
||||
|
||||
instruct string_compareU(rarg1RegP str1, rarg2RegP str2, rarg3RegI cnt1, rarg4RegI cnt2, iRegIdst result,
|
||||
iRegIdst tmp, regCTR ctr, flagsRegCR0 cr0) %{
|
||||
predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::UU);
|
||||
match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
|
||||
effect(TEMP_DEF result, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL ctr, KILL cr0, TEMP tmp);
|
||||
ins_cost(300);
|
||||
format %{ "String Compare char[] $str1,$cnt1,$str2,$cnt2 -> $result \t// KILL $tmp" %}
|
||||
ins_encode %{
|
||||
// TODO: PPC port $archOpcode(ppc64Opcode_compound);
|
||||
__ string_compare($str1$$Register, $str2$$Register,
|
||||
$cnt1$$Register, $cnt2$$Register,
|
||||
$tmp$$Register,
|
||||
$result$$Register, StrIntrinsicNode::UU);
|
||||
%}
|
||||
ins_pipe(pipe_class_default);
|
||||
%}
|
||||
|
||||
instruct string_compareLU(rarg1RegP str1, rarg2RegP str2, rarg3RegI cnt1, rarg4RegI cnt2, iRegIdst result,
|
||||
iRegIdst tmp, regCTR ctr, flagsRegCR0 cr0) %{
|
||||
predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::LU);
|
||||
match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
|
||||
effect(TEMP_DEF result, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL ctr, KILL cr0, TEMP tmp);
|
||||
ins_cost(300);
|
||||
format %{ "String Compare byte[] $str1,$cnt1,$str2,$cnt2 -> $result \t// KILL $tmp" %}
|
||||
ins_encode %{
|
||||
// TODO: PPC port $archOpcode(ppc64Opcode_compound);
|
||||
__ string_compare($str1$$Register, $str2$$Register,
|
||||
$cnt1$$Register, $cnt2$$Register,
|
||||
$tmp$$Register,
|
||||
$result$$Register, StrIntrinsicNode::LU);
|
||||
%}
|
||||
ins_pipe(pipe_class_default);
|
||||
%}
|
||||
|
||||
instruct string_compareUL(rarg1RegP str1, rarg2RegP str2, rarg3RegI cnt1, rarg4RegI cnt2, iRegIdst result,
|
||||
iRegIdst tmp, regCTR ctr, flagsRegCR0 cr0) %{
|
||||
predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::UL);
|
||||
match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
|
||||
effect(TEMP_DEF result, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL ctr, KILL cr0, TEMP tmp);
|
||||
ins_cost(300);
|
||||
format %{ "String Compare byte[] $str1,$cnt1,$str2,$cnt2 -> $result \t// KILL $tmp" %}
|
||||
ins_encode %{
|
||||
// TODO: PPC port $archOpcode(ppc64Opcode_compound);
|
||||
__ string_compare($str2$$Register, $str1$$Register,
|
||||
$cnt2$$Register, $cnt1$$Register,
|
||||
$tmp$$Register,
|
||||
$result$$Register, StrIntrinsicNode::UL);
|
||||
%}
|
||||
ins_pipe(pipe_class_default);
|
||||
%}
|
||||
|
||||
instruct string_equalsL(rarg1RegP str1, rarg2RegP str2, rarg3RegI cnt, iRegIdst result,
|
||||
iRegIdst tmp, regCTR ctr, flagsRegCR0 cr0) %{
|
||||
predicate(((StrEqualsNode*)n)->encoding() == StrIntrinsicNode::LL);
|
||||
match(Set result (StrEquals (Binary str1 str2) cnt));
|
||||
effect(TEMP_DEF result, USE_KILL str1, USE_KILL str2, USE_KILL cnt, TEMP tmp, KILL ctr, KILL cr0);
|
||||
ins_cost(300);
|
||||
format %{ "String Equals byte[] $str1,$str2,$cnt -> $result \t// KILL $tmp" %}
|
||||
ins_encode %{
|
||||
// TODO: PPC port $archOpcode(ppc64Opcode_compound);
|
||||
__ array_equals(false, $str1$$Register, $str2$$Register,
|
||||
$cnt$$Register, $tmp$$Register,
|
||||
$result$$Register, true /* byte */);
|
||||
%}
|
||||
ins_pipe(pipe_class_default);
|
||||
%}
|
||||
|
||||
instruct string_equalsU(rarg1RegP str1, rarg2RegP str2, rarg3RegI cnt, iRegIdst result,
|
||||
iRegIdst tmp, regCTR ctr, flagsRegCR0 cr0) %{
|
||||
predicate(((StrEqualsNode*)n)->encoding() == StrIntrinsicNode::UU);
|
||||
match(Set result (StrEquals (Binary str1 str2) cnt));
|
||||
effect(TEMP_DEF result, USE_KILL str1, USE_KILL str2, USE_KILL cnt, TEMP tmp, KILL ctr, KILL cr0);
|
||||
ins_cost(300);
|
||||
format %{ "String Equals char[] $str1,$str2,$cnt -> $result \t// KILL $tmp" %}
|
||||
ins_encode %{
|
||||
// TODO: PPC port $archOpcode(ppc64Opcode_compound);
|
||||
__ array_equals(false, $str1$$Register, $str2$$Register,
|
||||
$cnt$$Register, $tmp$$Register,
|
||||
$result$$Register, false /* byte */);
|
||||
%}
|
||||
ins_pipe(pipe_class_default);
|
||||
%}
|
||||
|
||||
instruct array_equalsB(rarg1RegP ary1, rarg2RegP ary2, iRegIdst result,
|
||||
iRegIdst tmp1, iRegIdst tmp2, regCTR ctr, flagsRegCR0 cr0, flagsRegCR0 cr1) %{
|
||||
predicate(((AryEqNode*)n)->encoding() == StrIntrinsicNode::LL);
|
||||
match(Set result (AryEq ary1 ary2));
|
||||
effect(TEMP_DEF result, USE_KILL ary1, USE_KILL ary2, TEMP tmp1, TEMP tmp2, KILL ctr, KILL cr0, KILL cr1);
|
||||
ins_cost(300);
|
||||
format %{ "Array Equals $ary1,$ary2 -> $result \t// KILL $tmp1,$tmp2" %}
|
||||
ins_encode %{
|
||||
// TODO: PPC port $archOpcode(ppc64Opcode_compound);
|
||||
__ array_equals(true, $ary1$$Register, $ary2$$Register,
|
||||
$tmp1$$Register, $tmp2$$Register,
|
||||
$result$$Register, true /* byte */);
|
||||
%}
|
||||
ins_pipe(pipe_class_default);
|
||||
%}
|
||||
|
||||
instruct array_equalsC(rarg1RegP ary1, rarg2RegP ary2, iRegIdst result,
|
||||
iRegIdst tmp1, iRegIdst tmp2, regCTR ctr, flagsRegCR0 cr0, flagsRegCR0 cr1) %{
|
||||
predicate(((AryEqNode*)n)->encoding() == StrIntrinsicNode::UU);
|
||||
match(Set result (AryEq ary1 ary2));
|
||||
effect(TEMP_DEF result, USE_KILL ary1, USE_KILL ary2, TEMP tmp1, TEMP tmp2, KILL ctr, KILL cr0, KILL cr1);
|
||||
ins_cost(300);
|
||||
format %{ "Array Equals $ary1,$ary2 -> $result \t// KILL $tmp1,$tmp2" %}
|
||||
ins_encode %{
|
||||
// TODO: PPC port $archOpcode(ppc64Opcode_compound);
|
||||
__ array_equals(true, $ary1$$Register, $ary2$$Register,
|
||||
$tmp1$$Register, $tmp2$$Register,
|
||||
$result$$Register, false /* byte */);
|
||||
%}
|
||||
ins_pipe(pipe_class_default);
|
||||
%}
|
||||
|
||||
instruct indexOf_imm1_char_U(iRegIdst result, iRegPsrc haystack, iRegIsrc haycnt,
|
||||
immP needleImm, immL offsetImm, immI_1 needlecntImm,
|
||||
iRegIdst tmp1, iRegIdst tmp2,
|
||||
flagsRegCR0 cr0, flagsRegCR1 cr1, regCTR ctr) %{
|
||||
match(Set result (StrIndexOf (Binary haystack haycnt) (Binary (AddP needleImm offsetImm) needlecntImm)));
|
||||
effect(TEMP tmp1, TEMP tmp2, KILL cr0, KILL cr1, KILL ctr);
|
||||
// Required for EA: check if it is still a type_array.
|
||||
predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UU);
|
||||
ins_cost(150);
|
||||
|
||||
format %{ "String IndexOf CSCL1 $haystack[0..$haycnt], $needleImm+$offsetImm[0..$needlecntImm]"
|
||||
"-> $result \t// KILL $haycnt, $tmp1, $tmp2, $cr0, $cr1" %}
|
||||
|
||||
ins_encode %{
|
||||
// TODO: PPC port $archOpcode(ppc64Opcode_compound);
|
||||
immPOper *needleOper = (immPOper *)$needleImm;
|
||||
const TypeOopPtr *t = needleOper->type()->isa_oopptr();
|
||||
ciTypeArray* needle_values = t->const_oop()->as_type_array(); // Pointer to live char *
|
||||
jchar chr;
|
||||
#ifdef VM_LITTLE_ENDIAN
|
||||
chr = (((jchar)(unsigned char)needle_values->element_value(1).as_byte()) << 8) |
|
||||
((jchar)(unsigned char)needle_values->element_value(0).as_byte());
|
||||
#else
|
||||
chr = (((jchar)(unsigned char)needle_values->element_value(0).as_byte()) << 8) |
|
||||
((jchar)(unsigned char)needle_values->element_value(1).as_byte());
|
||||
#endif
|
||||
__ string_indexof_char($result$$Register,
|
||||
$haystack$$Register, $haycnt$$Register,
|
||||
R0, chr,
|
||||
$tmp1$$Register, $tmp2$$Register, false /*is_byte*/);
|
||||
%}
|
||||
ins_pipe(pipe_class_compare);
|
||||
%}
|
||||
|
||||
instruct indexOf_imm1_char_L(iRegIdst result, iRegPsrc haystack, iRegIsrc haycnt,
|
||||
immP needleImm, immL offsetImm, immI_1 needlecntImm,
|
||||
iRegIdst tmp1, iRegIdst tmp2,
|
||||
flagsRegCR0 cr0, flagsRegCR1 cr1, regCTR ctr) %{
|
||||
match(Set result (StrIndexOf (Binary haystack haycnt) (Binary (AddP needleImm offsetImm) needlecntImm)));
|
||||
effect(TEMP tmp1, TEMP tmp2, KILL cr0, KILL cr1, KILL ctr);
|
||||
// Required for EA: check if it is still a type_array.
|
||||
predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::LL);
|
||||
ins_cost(150);
|
||||
|
||||
format %{ "String IndexOf CSCL1 $haystack[0..$haycnt], $needleImm+$offsetImm[0..$needlecntImm]"
|
||||
"-> $result \t// KILL $haycnt, $tmp1, $tmp2, $cr0, $cr1" %}
|
||||
|
||||
ins_encode %{
|
||||
// TODO: PPC port $archOpcode(ppc64Opcode_compound);
|
||||
immPOper *needleOper = (immPOper *)$needleImm;
|
||||
const TypeOopPtr *t = needleOper->type()->isa_oopptr();
|
||||
ciTypeArray* needle_values = t->const_oop()->as_type_array(); // Pointer to live char *
|
||||
jchar chr = (jchar)needle_values->element_value(0).as_byte();
|
||||
__ string_indexof_char($result$$Register,
|
||||
$haystack$$Register, $haycnt$$Register,
|
||||
R0, chr,
|
||||
$tmp1$$Register, $tmp2$$Register, true /*is_byte*/);
|
||||
%}
|
||||
ins_pipe(pipe_class_compare);
|
||||
%}
|
||||
|
||||
instruct indexOf_imm1_char_UL(iRegIdst result, iRegPsrc haystack, iRegIsrc haycnt,
|
||||
immP needleImm, immL offsetImm, immI_1 needlecntImm,
|
||||
iRegIdst tmp1, iRegIdst tmp2,
|
||||
flagsRegCR0 cr0, flagsRegCR1 cr1, regCTR ctr) %{
|
||||
match(Set result (StrIndexOf (Binary haystack haycnt) (Binary (AddP needleImm offsetImm) needlecntImm)));
|
||||
effect(TEMP tmp1, TEMP tmp2, KILL cr0, KILL cr1, KILL ctr);
|
||||
// Required for EA: check if it is still a type_array.
|
||||
predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UL);
|
||||
ins_cost(150);
|
||||
|
||||
format %{ "String IndexOf CSCL1 $haystack[0..$haycnt], $needleImm+$offsetImm[0..$needlecntImm]"
|
||||
"-> $result \t// KILL $haycnt, $tmp1, $tmp2, $cr0, $cr1" %}
|
||||
|
||||
ins_encode %{
|
||||
// TODO: PPC port $archOpcode(ppc64Opcode_compound);
|
||||
immPOper *needleOper = (immPOper *)$needleImm;
|
||||
const TypeOopPtr *t = needleOper->type()->isa_oopptr();
|
||||
ciTypeArray* needle_values = t->const_oop()->as_type_array(); // Pointer to live char *
|
||||
jchar chr = (jchar)needle_values->element_value(0).as_byte();
|
||||
__ string_indexof_char($result$$Register,
|
||||
$haystack$$Register, $haycnt$$Register,
|
||||
R0, chr,
|
||||
$tmp1$$Register, $tmp2$$Register, false /*is_byte*/);
|
||||
%}
|
||||
ins_pipe(pipe_class_compare);
|
||||
%}
|
||||
|
||||
instruct indexOf_imm1_U(iRegIdst result, iRegPsrc haystack, iRegIsrc haycnt,
|
||||
rscratch2RegP needle, immI_1 needlecntImm,
|
||||
iRegIdst tmp1, iRegIdst tmp2,
|
||||
flagsRegCR0 cr0, flagsRegCR1 cr1, regCTR ctr) %{
|
||||
match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecntImm)));
|
||||
effect(USE_KILL needle, TEMP tmp1, TEMP tmp2, KILL cr0, KILL cr1, KILL ctr);
|
||||
// Required for EA: check if it is still a type_array.
|
||||
predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UU &&
|
||||
n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop() &&
|
||||
n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop()->is_type_array());
|
||||
ins_cost(180);
|
||||
|
||||
format %{ "String IndexOf SCL1 $haystack[0..$haycnt], $needle[0..$needlecntImm]"
|
||||
" -> $result \t// KILL $haycnt, $needle, $tmp1, $tmp2, $cr0, $cr1" %}
|
||||
ins_encode %{
|
||||
// TODO: PPC port $archOpcode(ppc64Opcode_compound);
|
||||
Node *ndl = in(operand_index($needle)); // The node that defines needle.
|
||||
ciTypeArray* needle_values = ndl->bottom_type()->is_aryptr()->const_oop()->as_type_array();
|
||||
guarantee(needle_values, "sanity");
|
||||
jchar chr;
|
||||
#ifdef VM_LITTLE_ENDIAN
|
||||
chr = (((jchar)(unsigned char)needle_values->element_value(1).as_byte()) << 8) |
|
||||
((jchar)(unsigned char)needle_values->element_value(0).as_byte());
|
||||
#else
|
||||
chr = (((jchar)(unsigned char)needle_values->element_value(0).as_byte()) << 8) |
|
||||
((jchar)(unsigned char)needle_values->element_value(1).as_byte());
|
||||
#endif
|
||||
__ string_indexof_char($result$$Register,
|
||||
$haystack$$Register, $haycnt$$Register,
|
||||
R0, chr,
|
||||
$tmp1$$Register, $tmp2$$Register, false /*is_byte*/);
|
||||
%}
|
||||
ins_pipe(pipe_class_compare);
|
||||
%}
|
||||
|
||||
instruct indexOf_imm1_L(iRegIdst result, iRegPsrc haystack, iRegIsrc haycnt,
|
||||
rscratch2RegP needle, immI_1 needlecntImm,
|
||||
iRegIdst tmp1, iRegIdst tmp2,
|
||||
flagsRegCR0 cr0, flagsRegCR1 cr1, regCTR ctr) %{
|
||||
match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecntImm)));
|
||||
effect(USE_KILL needle, TEMP tmp1, TEMP tmp2, KILL cr0, KILL cr1, KILL ctr);
|
||||
// Required for EA: check if it is still a type_array.
|
||||
predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::LL &&
|
||||
n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop() &&
|
||||
n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop()->is_type_array());
|
||||
ins_cost(180);
|
||||
|
||||
format %{ "String IndexOf SCL1 $haystack[0..$haycnt], $needle[0..$needlecntImm]"
|
||||
" -> $result \t// KILL $haycnt, $needle, $tmp1, $tmp2, $cr0, $cr1" %}
|
||||
ins_encode %{
|
||||
// TODO: PPC port $archOpcode(ppc64Opcode_compound);
|
||||
Node *ndl = in(operand_index($needle)); // The node that defines needle.
|
||||
ciTypeArray* needle_values = ndl->bottom_type()->is_aryptr()->const_oop()->as_type_array();
|
||||
guarantee(needle_values, "sanity");
|
||||
jchar chr = (jchar)needle_values->element_value(0).as_byte();
|
||||
__ string_indexof_char($result$$Register,
|
||||
$haystack$$Register, $haycnt$$Register,
|
||||
R0, chr,
|
||||
$tmp1$$Register, $tmp2$$Register, true /*is_byte*/);
|
||||
%}
|
||||
ins_pipe(pipe_class_compare);
|
||||
%}
|
||||
|
||||
instruct indexOf_imm1_UL(iRegIdst result, iRegPsrc haystack, iRegIsrc haycnt,
|
||||
rscratch2RegP needle, immI_1 needlecntImm,
|
||||
iRegIdst tmp1, iRegIdst tmp2,
|
||||
flagsRegCR0 cr0, flagsRegCR1 cr1, regCTR ctr) %{
|
||||
match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecntImm)));
|
||||
effect(USE_KILL needle, TEMP tmp1, TEMP tmp2, KILL cr0, KILL cr1, KILL ctr);
|
||||
// Required for EA: check if it is still a type_array.
|
||||
predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UL &&
|
||||
n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop() &&
|
||||
n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop()->is_type_array());
|
||||
ins_cost(180);
|
||||
|
||||
format %{ "String IndexOf SCL1 $haystack[0..$haycnt], $needle[0..$needlecntImm]"
|
||||
" -> $result \t// KILL $haycnt, $needle, $tmp1, $tmp2, $cr0, $cr1" %}
|
||||
ins_encode %{
|
||||
// TODO: PPC port $archOpcode(ppc64Opcode_compound);
|
||||
Node *ndl = in(operand_index($needle)); // The node that defines needle.
|
||||
ciTypeArray* needle_values = ndl->bottom_type()->is_aryptr()->const_oop()->as_type_array();
|
||||
guarantee(needle_values, "sanity");
|
||||
jchar chr = (jchar)needle_values->element_value(0).as_byte();
|
||||
__ string_indexof_char($result$$Register,
|
||||
$haystack$$Register, $haycnt$$Register,
|
||||
R0, chr,
|
||||
$tmp1$$Register, $tmp2$$Register, false /*is_byte*/);
|
||||
%}
|
||||
ins_pipe(pipe_class_compare);
|
||||
%}
|
||||
|
||||
instruct indexOfChar_U(iRegIdst result, iRegPsrc haystack, iRegIsrc haycnt,
|
||||
iRegIsrc ch, iRegIdst tmp1, iRegIdst tmp2,
|
||||
flagsRegCR0 cr0, flagsRegCR1 cr1, regCTR ctr) %{
|
||||
match(Set result (StrIndexOfChar (Binary haystack haycnt) ch));
|
||||
effect(TEMP tmp1, TEMP tmp2, KILL cr0, KILL cr1, KILL ctr);
|
||||
predicate(CompactStrings);
|
||||
ins_cost(180);
|
||||
|
||||
format %{ "String IndexOfChar $haystack[0..$haycnt], $ch"
|
||||
" -> $result \t// KILL $haycnt, $tmp1, $tmp2, $cr0, $cr1" %}
|
||||
ins_encode %{
|
||||
// TODO: PPC port $archOpcode(ppc64Opcode_compound);
|
||||
__ string_indexof_char($result$$Register,
|
||||
$haystack$$Register, $haycnt$$Register,
|
||||
$ch$$Register, 0 /* this is not used if the character is already in a register */,
|
||||
$tmp1$$Register, $tmp2$$Register, false /*is_byte*/);
|
||||
%}
|
||||
ins_pipe(pipe_class_compare);
|
||||
%}
|
||||
|
||||
instruct indexOf_imm_U(iRegIdst result, iRegPsrc haystack, rscratch1RegI haycnt,
|
||||
iRegPsrc needle, uimmI15 needlecntImm,
|
||||
iRegIdst tmp1, iRegIdst tmp2, iRegIdst tmp3, iRegIdst tmp4, iRegIdst tmp5,
|
||||
flagsRegCR0 cr0, flagsRegCR1 cr1, flagsRegCR6 cr6, regCTR ctr) %{
|
||||
match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecntImm)));
|
||||
effect(USE_KILL haycnt, /* better: TDEF haycnt, */ TEMP_DEF result,
|
||||
TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, KILL cr0, KILL cr1, KILL cr6, KILL ctr);
|
||||
// Required for EA: check if it is still a type_array.
|
||||
predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UU &&
|
||||
n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop() &&
|
||||
n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop()->is_type_array());
|
||||
ins_cost(250);
|
||||
|
||||
format %{ "String IndexOf SCL $haystack[0..$haycnt], $needle[0..$needlecntImm]"
|
||||
" -> $result \t// KILL $haycnt, $tmp1, $tmp2, $tmp3, $tmp4, $tmp5, $cr0, $cr1" %}
|
||||
ins_encode %{
|
||||
// TODO: PPC port $archOpcode(ppc64Opcode_compound);
|
||||
Node *ndl = in(operand_index($needle)); // The node that defines needle.
|
||||
ciTypeArray* needle_values = ndl->bottom_type()->is_aryptr()->const_oop()->as_type_array();
|
||||
|
||||
__ string_indexof($result$$Register,
|
||||
$haystack$$Register, $haycnt$$Register,
|
||||
$needle$$Register, needle_values, $tmp5$$Register, $needlecntImm$$constant,
|
||||
$tmp1$$Register, $tmp2$$Register, $tmp3$$Register, $tmp4$$Register, StrIntrinsicNode::UU);
|
||||
%}
|
||||
ins_pipe(pipe_class_compare);
|
||||
%}
|
||||
|
||||
instruct indexOf_imm_L(iRegIdst result, iRegPsrc haystack, rscratch1RegI haycnt,
|
||||
iRegPsrc needle, uimmI15 needlecntImm,
|
||||
iRegIdst tmp1, iRegIdst tmp2, iRegIdst tmp3, iRegIdst tmp4, iRegIdst tmp5,
|
||||
flagsRegCR0 cr0, flagsRegCR1 cr1, flagsRegCR6 cr6, regCTR ctr) %{
|
||||
match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecntImm)));
|
||||
effect(USE_KILL haycnt, /* better: TDEF haycnt, */ TEMP_DEF result,
|
||||
TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, KILL cr0, KILL cr1, KILL cr6, KILL ctr);
|
||||
// Required for EA: check if it is still a type_array.
|
||||
predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::LL &&
|
||||
n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop() &&
|
||||
n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop()->is_type_array());
|
||||
ins_cost(250);
|
||||
|
||||
format %{ "String IndexOf SCL $haystack[0..$haycnt], $needle[0..$needlecntImm]"
|
||||
" -> $result \t// KILL $haycnt, $tmp1, $tmp2, $tmp3, $tmp4, $tmp5, $cr0, $cr1" %}
|
||||
ins_encode %{
|
||||
// TODO: PPC port $archOpcode(ppc64Opcode_compound);
|
||||
Node *ndl = in(operand_index($needle)); // The node that defines needle.
|
||||
ciTypeArray* needle_values = ndl->bottom_type()->is_aryptr()->const_oop()->as_type_array();
|
||||
|
||||
__ string_indexof($result$$Register,
|
||||
$haystack$$Register, $haycnt$$Register,
|
||||
$needle$$Register, needle_values, $tmp5$$Register, $needlecntImm$$constant,
|
||||
$tmp1$$Register, $tmp2$$Register, $tmp3$$Register, $tmp4$$Register, StrIntrinsicNode::LL);
|
||||
%}
|
||||
ins_pipe(pipe_class_compare);
|
||||
%}
|
||||
|
||||
instruct indexOf_imm_UL(iRegIdst result, iRegPsrc haystack, rscratch1RegI haycnt,
|
||||
iRegPsrc needle, uimmI15 needlecntImm,
|
||||
iRegIdst tmp1, iRegIdst tmp2, iRegIdst tmp3, iRegIdst tmp4, iRegIdst tmp5,
|
||||
flagsRegCR0 cr0, flagsRegCR1 cr1, flagsRegCR6 cr6, regCTR ctr) %{
|
||||
match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecntImm)));
|
||||
effect(USE_KILL haycnt, /* better: TDEF haycnt, */ TEMP_DEF result,
|
||||
TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, KILL cr0, KILL cr1, KILL cr6, KILL ctr);
|
||||
// Required for EA: check if it is still a type_array.
|
||||
predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UL &&
|
||||
n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop() &&
|
||||
n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop()->is_type_array());
|
||||
ins_cost(250);
|
||||
|
||||
format %{ "String IndexOf SCL $haystack[0..$haycnt], $needle[0..$needlecntImm]"
|
||||
" -> $result \t// KILL $haycnt, $tmp1, $tmp2, $tmp3, $tmp4, $tmp5, $cr0, $cr1" %}
|
||||
ins_encode %{
|
||||
// TODO: PPC port $archOpcode(ppc64Opcode_compound);
|
||||
Node *ndl = in(operand_index($needle)); // The node that defines needle.
|
||||
ciTypeArray* needle_values = ndl->bottom_type()->is_aryptr()->const_oop()->as_type_array();
|
||||
|
||||
__ string_indexof($result$$Register,
|
||||
$haystack$$Register, $haycnt$$Register,
|
||||
$needle$$Register, needle_values, $tmp5$$Register, $needlecntImm$$constant,
|
||||
$tmp1$$Register, $tmp2$$Register, $tmp3$$Register, $tmp4$$Register, StrIntrinsicNode::UL);
|
||||
%}
|
||||
ins_pipe(pipe_class_compare);
|
||||
%}
|
||||
|
||||
instruct indexOf_U(iRegIdst result, iRegPsrc haystack, rscratch1RegI haycnt, iRegPsrc needle, rscratch2RegI needlecnt,
|
||||
iRegLdst tmp1, iRegLdst tmp2, iRegLdst tmp3, iRegLdst tmp4,
|
||||
flagsRegCR0 cr0, flagsRegCR1 cr1, flagsRegCR6 cr6, regCTR ctr) %{
|
||||
match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecnt)));
|
||||
effect(USE_KILL haycnt, USE_KILL needlecnt, /*better: TDEF haycnt, TDEF needlecnt,*/
|
||||
TEMP_DEF result,
|
||||
TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, KILL cr0, KILL cr1, KILL cr6, KILL ctr);
|
||||
predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UU);
|
||||
ins_cost(300);
|
||||
|
||||
format %{ "String IndexOf $haystack[0..$haycnt], $needle[0..$needlecnt]"
|
||||
" -> $result \t// KILL $haycnt, $needlecnt, $tmp1, $tmp2, $tmp3, $tmp4, $cr0, $cr1" %}
|
||||
ins_encode %{
|
||||
// TODO: PPC port $archOpcode(ppc64Opcode_compound);
|
||||
__ string_indexof($result$$Register,
|
||||
$haystack$$Register, $haycnt$$Register,
|
||||
$needle$$Register, NULL, $needlecnt$$Register, 0, // needlecnt not constant.
|
||||
$tmp1$$Register, $tmp2$$Register, $tmp3$$Register, $tmp4$$Register, StrIntrinsicNode::UU);
|
||||
%}
|
||||
ins_pipe(pipe_class_compare);
|
||||
%}
|
||||
|
||||
instruct indexOf_L(iRegIdst result, iRegPsrc haystack, rscratch1RegI haycnt, iRegPsrc needle, rscratch2RegI needlecnt,
|
||||
iRegLdst tmp1, iRegLdst tmp2, iRegLdst tmp3, iRegLdst tmp4,
|
||||
flagsRegCR0 cr0, flagsRegCR1 cr1, flagsRegCR6 cr6, regCTR ctr) %{
|
||||
match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecnt)));
|
||||
effect(USE_KILL haycnt, USE_KILL needlecnt, /*better: TDEF haycnt, TDEF needlecnt,*/
|
||||
TEMP_DEF result,
|
||||
TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, KILL cr0, KILL cr1, KILL cr6, KILL ctr);
|
||||
predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::LL);
|
||||
ins_cost(300);
|
||||
|
||||
format %{ "String IndexOf $haystack[0..$haycnt], $needle[0..$needlecnt]"
|
||||
" -> $result \t// KILL $haycnt, $needlecnt, $tmp1, $tmp2, $tmp3, $tmp4, $cr0, $cr1" %}
|
||||
ins_encode %{
|
||||
// TODO: PPC port $archOpcode(ppc64Opcode_compound);
|
||||
__ string_indexof($result$$Register,
|
||||
$haystack$$Register, $haycnt$$Register,
|
||||
$needle$$Register, NULL, $needlecnt$$Register, 0, // needlecnt not constant.
|
||||
$tmp1$$Register, $tmp2$$Register, $tmp3$$Register, $tmp4$$Register, StrIntrinsicNode::LL);
|
||||
%}
|
||||
ins_pipe(pipe_class_compare);
|
||||
%}
|
||||
|
||||
instruct indexOf_UL(iRegIdst result, iRegPsrc haystack, rscratch1RegI haycnt, iRegPsrc needle, rscratch2RegI needlecnt,
|
||||
iRegLdst tmp1, iRegLdst tmp2, iRegLdst tmp3, iRegLdst tmp4,
|
||||
flagsRegCR0 cr0, flagsRegCR1 cr1, flagsRegCR6 cr6, regCTR ctr) %{
|
||||
match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecnt)));
|
||||
effect(USE_KILL haycnt, USE_KILL needlecnt, /*better: TDEF haycnt, TDEF needlecnt,*/
|
||||
TEMP_DEF result,
|
||||
TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, KILL cr0, KILL cr1, KILL cr6, KILL ctr);
|
||||
predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UL);
|
||||
ins_cost(300);
|
||||
|
||||
format %{ "String IndexOf $haystack[0..$haycnt], $needle[0..$needlecnt]"
|
||||
" -> $result \t// KILL $haycnt, $needlecnt, $tmp1, $tmp2, $tmp3, $tmp4, $cr0, $cr1" %}
|
||||
ins_encode %{
|
||||
// TODO: PPC port $archOpcode(ppc64Opcode_compound);
|
||||
__ string_indexof($result$$Register,
|
||||
$haystack$$Register, $haycnt$$Register,
|
||||
$needle$$Register, NULL, $needlecnt$$Register, 0, // needlecnt not constant.
|
||||
$tmp1$$Register, $tmp2$$Register, $tmp3$$Register, $tmp4$$Register, StrIntrinsicNode::UL);
|
||||
%}
|
||||
ins_pipe(pipe_class_compare);
|
||||
%}
|
||||
|
||||
// char[] to byte[] compression
|
||||
instruct string_compress(rarg1RegP src, rarg2RegP dst, iRegIsrc len, iRegIdst result, iRegLdst tmp1,
|
||||
iRegLdst tmp2, iRegLdst tmp3, iRegLdst tmp4, iRegLdst tmp5, regCTR ctr, flagsRegCR0 cr0) %{
|
||||
match(Set result (StrCompressedCopy src (Binary dst len)));
|
||||
effect(TEMP_DEF result, TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5,
|
||||
USE_KILL src, USE_KILL dst, KILL ctr, KILL cr0);
|
||||
ins_cost(300);
|
||||
format %{ "String Compress $src,$dst,$len -> $result \t// KILL $tmp1, $tmp2, $tmp3, $tmp4, $tmp5" %}
|
||||
ins_encode %{
|
||||
// TODO: PPC port $archOpcode(ppc64Opcode_compound);
|
||||
Label Lskip, Ldone;
|
||||
__ li($result$$Register, 0);
|
||||
__ string_compress_16($src$$Register, $dst$$Register, $len$$Register, $tmp1$$Register,
|
||||
$tmp2$$Register, $tmp3$$Register, $tmp4$$Register, $tmp5$$Register, Ldone);
|
||||
__ rldicl_($tmp1$$Register, $len$$Register, 0, 64-3); // Remaining characters.
|
||||
__ beq(CCR0, Lskip);
|
||||
__ string_compress($src$$Register, $dst$$Register, $tmp1$$Register, $tmp2$$Register, Ldone);
|
||||
__ bind(Lskip);
|
||||
__ mr($result$$Register, $len$$Register);
|
||||
__ bind(Ldone);
|
||||
%}
|
||||
ins_pipe(pipe_class_default);
|
||||
%}
|
||||
|
||||
// byte[] to char[] inflation
|
||||
instruct string_inflate(Universe dummy, rarg1RegP src, rarg2RegP dst, iRegIsrc len, iRegLdst tmp1,
|
||||
iRegLdst tmp2, iRegLdst tmp3, iRegLdst tmp4, iRegLdst tmp5, regCTR ctr, flagsRegCR0 cr0) %{
|
||||
match(Set dummy (StrInflatedCopy src (Binary dst len)));
|
||||
effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, USE_KILL src, USE_KILL dst, KILL ctr, KILL cr0);
|
||||
ins_cost(300);
|
||||
format %{ "String Inflate $src,$dst,$len \t// KILL $tmp1, $tmp2, $tmp3, $tmp4, $tmp5" %}
|
||||
ins_encode %{
|
||||
// TODO: PPC port $archOpcode(ppc64Opcode_compound);
|
||||
Label Ldone;
|
||||
__ string_inflate_16($src$$Register, $dst$$Register, $len$$Register, $tmp1$$Register,
|
||||
$tmp2$$Register, $tmp3$$Register, $tmp4$$Register, $tmp5$$Register);
|
||||
__ rldicl_($tmp1$$Register, $len$$Register, 0, 64-3); // Remaining characters.
|
||||
__ beq(CCR0, Ldone);
|
||||
__ string_inflate($src$$Register, $dst$$Register, $tmp1$$Register, $tmp2$$Register);
|
||||
__ bind(Ldone);
|
||||
%}
|
||||
ins_pipe(pipe_class_default);
|
||||
%}
|
||||
|
||||
// StringCoding.java intrinsics
|
||||
instruct has_negatives(rarg1RegP ary1, iRegIsrc len, iRegIdst result, iRegLdst tmp1, iRegLdst tmp2,
|
||||
regCTR ctr, flagsRegCR0 cr0)
|
||||
%{
|
||||
match(Set result (HasNegatives ary1 len));
|
||||
effect(TEMP_DEF result, USE_KILL ary1, TEMP tmp1, TEMP tmp2, KILL ctr, KILL cr0);
|
||||
ins_cost(300);
|
||||
format %{ "has negatives byte[] $ary1,$len -> $result \t// KILL $tmp1, $tmp2" %}
|
||||
ins_encode %{
|
||||
// TODO: PPC port $archOpcode(ppc64Opcode_compound);
|
||||
__ has_negatives($ary1$$Register, $len$$Register, $result$$Register,
|
||||
$tmp1$$Register, $tmp2$$Register);
|
||||
%}
|
||||
ins_pipe(pipe_class_default);
|
||||
%}
|
||||
|
||||
// encode char[] to byte[] in ISO_8859_1
|
||||
instruct encode_iso_array(rarg1RegP src, rarg2RegP dst, iRegIsrc len, iRegIdst result, iRegLdst tmp1,
|
||||
iRegLdst tmp2, iRegLdst tmp3, iRegLdst tmp4, iRegLdst tmp5, regCTR ctr, flagsRegCR0 cr0) %{
|
||||
match(Set result (EncodeISOArray src (Binary dst len)));
|
||||
effect(TEMP_DEF result, TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5,
|
||||
USE_KILL src, USE_KILL dst, KILL ctr, KILL cr0);
|
||||
ins_cost(300);
|
||||
format %{ "Encode array $src,$dst,$len -> $result \t// KILL $tmp1, $tmp2, $tmp3, $tmp4, $tmp5" %}
|
||||
ins_encode %{
|
||||
// TODO: PPC port $archOpcode(ppc64Opcode_compound);
|
||||
Label Lslow, Lfailure1, Lfailure2, Ldone;
|
||||
__ string_compress_16($src$$Register, $dst$$Register, $len$$Register, $tmp1$$Register,
|
||||
$tmp2$$Register, $tmp3$$Register, $tmp4$$Register, $tmp5$$Register, Lfailure1);
|
||||
__ rldicl_($result$$Register, $len$$Register, 0, 64-3); // Remaining characters.
|
||||
__ beq(CCR0, Ldone);
|
||||
__ bind(Lslow);
|
||||
__ string_compress($src$$Register, $dst$$Register, $result$$Register, $tmp2$$Register, Lfailure2);
|
||||
__ li($result$$Register, 0);
|
||||
__ b(Ldone);
|
||||
|
||||
__ bind(Lfailure1);
|
||||
__ mr($result$$Register, $len$$Register);
|
||||
__ mfctr($tmp1$$Register);
|
||||
__ rldimi_($result$$Register, $tmp1$$Register, 3, 0); // Remaining characters.
|
||||
__ beq(CCR0, Ldone);
|
||||
__ b(Lslow);
|
||||
|
||||
__ bind(Lfailure2);
|
||||
__ mfctr($result$$Register); // Remaining characters.
|
||||
|
||||
__ bind(Ldone);
|
||||
__ subf($result$$Register, $result$$Register, $len$$Register);
|
||||
%}
|
||||
ins_pipe(pipe_class_default);
|
||||
%}
|
||||
|
||||
|
||||
// String_IndexOf for needle of length 1.
|
||||
//
|
||||
// Match needle into immediate operands: no loadConP node needed. Saves one
|
||||
|
@ -11060,11 +11638,11 @@ instruct string_indexOf_imm1_char(iRegIdst result, iRegPsrc haystack, iRegIsrc h
|
|||
if (java_lang_String::has_coder_field()) {
|
||||
// New compact strings byte array strings
|
||||
#ifdef VM_LITTLE_ENDIAN
|
||||
chr = (((jchar)needle_values->element_value(1).as_byte()) << 8) |
|
||||
(jchar)needle_values->element_value(0).as_byte();
|
||||
chr = (((jchar)(unsigned char)needle_values->element_value(1).as_byte()) << 8) |
|
||||
((jchar)(unsigned char)needle_values->element_value(0).as_byte());
|
||||
#else
|
||||
chr = (((jchar)needle_values->element_value(0).as_byte()) << 8) |
|
||||
(jchar)needle_values->element_value(1).as_byte();
|
||||
chr = (((jchar)(unsigned char)needle_values->element_value(0).as_byte()) << 8) |
|
||||
((jchar)(unsigned char)needle_values->element_value(1).as_byte());
|
||||
#endif
|
||||
} else {
|
||||
// Old char array strings
|
||||
|
@ -11115,11 +11693,11 @@ instruct string_indexOf_imm1(iRegIdst result, iRegPsrc haystack, iRegIsrc haycnt
|
|||
if (java_lang_String::has_coder_field()) {
|
||||
// New compact strings byte array strings
|
||||
#ifdef VM_LITTLE_ENDIAN
|
||||
chr = (((jchar)needle_values->element_value(1).as_byte()) << 8) |
|
||||
(jchar)needle_values->element_value(0).as_byte();
|
||||
chr = (((jchar)(unsigned char)needle_values->element_value(1).as_byte()) << 8) |
|
||||
((jchar)(unsigned char)needle_values->element_value(0).as_byte());
|
||||
#else
|
||||
chr = (((jchar)needle_values->element_value(0).as_byte()) << 8) |
|
||||
(jchar)needle_values->element_value(1).as_byte();
|
||||
chr = (((jchar)(unsigned char)needle_values->element_value(0).as_byte()) << 8) |
|
||||
((jchar)(unsigned char)needle_values->element_value(1).as_byte());
|
||||
#endif
|
||||
} else {
|
||||
// Old char array strings
|
||||
|
@ -11321,6 +11899,20 @@ instruct minI_reg_reg_Ex(iRegIdst dst, iRegIsrc src1, iRegIsrc src2) %{
|
|||
%}
|
||||
%}
|
||||
|
||||
instruct minI_reg_reg_isel(iRegIdst dst, iRegIsrc src1, iRegIsrc src2, flagsRegCR0 cr0) %{
|
||||
match(Set dst (MinI src1 src2));
|
||||
effect(KILL cr0);
|
||||
predicate(VM_Version::has_isel());
|
||||
ins_cost(DEFAULT_COST*2);
|
||||
|
||||
ins_encode %{
|
||||
// TODO: PPC port $archOpcode(ppc64Opcode_compound);
|
||||
__ cmpw(CCR0, $src1$$Register, $src2$$Register);
|
||||
__ isel($dst$$Register, CCR0, Assembler::less, /*invert*/false, $src1$$Register, $src2$$Register);
|
||||
%}
|
||||
ins_pipe(pipe_class_default);
|
||||
%}
|
||||
|
||||
instruct maxI_reg_reg_Ex(iRegIdst dst, iRegIsrc src1, iRegIsrc src2) %{
|
||||
match(Set dst (MaxI src1 src2));
|
||||
ins_cost(DEFAULT_COST*6);
|
||||
|
@ -11341,6 +11933,20 @@ instruct maxI_reg_reg_Ex(iRegIdst dst, iRegIsrc src1, iRegIsrc src2) %{
|
|||
%}
|
||||
%}
|
||||
|
||||
instruct maxI_reg_reg_isel(iRegIdst dst, iRegIsrc src1, iRegIsrc src2, flagsRegCR0 cr0) %{
|
||||
match(Set dst (MaxI src1 src2));
|
||||
effect(KILL cr0);
|
||||
predicate(VM_Version::has_isel());
|
||||
ins_cost(DEFAULT_COST*2);
|
||||
|
||||
ins_encode %{
|
||||
// TODO: PPC port $archOpcode(ppc64Opcode_compound);
|
||||
__ cmpw(CCR0, $src1$$Register, $src2$$Register);
|
||||
__ isel($dst$$Register, CCR0, Assembler::greater, /*invert*/false, $src1$$Register, $src2$$Register);
|
||||
%}
|
||||
ins_pipe(pipe_class_default);
|
||||
%}
|
||||
|
||||
//---------- Population Count Instructions ------------------------------------
|
||||
|
||||
// Popcnt for Power7.
|
||||
|
|
|
@ -2609,9 +2609,7 @@ class StubGenerator: public StubCodeGenerator {
|
|||
* R5_ARG3 - int length (of buffer)
|
||||
*
|
||||
* scratch:
|
||||
* R6_ARG4 - crc table address
|
||||
* R7_ARG5 - tmp1
|
||||
* R8_ARG6 - tmp2
|
||||
* R2, R6-R12
|
||||
*
|
||||
* Ouput:
|
||||
* R3_RET - int crc result
|
||||
|
@ -2623,22 +2621,25 @@ class StubGenerator: public StubCodeGenerator {
|
|||
address start = __ function_entry(); // Remember stub start address (is rtn value).
|
||||
|
||||
// arguments to kernel_crc32:
|
||||
Register crc = R3_ARG1; // Current checksum, preset by caller or result from previous call.
|
||||
Register data = R4_ARG2; // source byte array
|
||||
Register dataLen = R5_ARG3; // #bytes to process
|
||||
Register table = R6_ARG4; // crc table address
|
||||
const Register crc = R3_ARG1; // Current checksum, preset by caller or result from previous call.
|
||||
const Register data = R4_ARG2; // source byte array
|
||||
const Register dataLen = R5_ARG3; // #bytes to process
|
||||
const Register table = R6_ARG4; // crc table address
|
||||
|
||||
Register t0 = R9; // work reg for kernel* emitters
|
||||
Register t1 = R10; // work reg for kernel* emitters
|
||||
Register t2 = R11; // work reg for kernel* emitters
|
||||
Register t3 = R12; // work reg for kernel* emitters
|
||||
const Register t0 = R2;
|
||||
const Register t1 = R7;
|
||||
const Register t2 = R8;
|
||||
const Register t3 = R9;
|
||||
const Register tc0 = R10;
|
||||
const Register tc1 = R11;
|
||||
const Register tc2 = R12;
|
||||
|
||||
BLOCK_COMMENT("Stub body {");
|
||||
assert_different_registers(crc, data, dataLen, table);
|
||||
|
||||
StubRoutines::ppc64::generate_load_crc_table_addr(_masm, table);
|
||||
|
||||
__ kernel_crc32_1byte(crc, data, dataLen, table, t0, t1, t2, t3);
|
||||
__ kernel_crc32_1word(crc, data, dataLen, table, t0, t1, t2, t3, tc0, tc1, tc2, table);
|
||||
|
||||
BLOCK_COMMENT("return");
|
||||
__ mr_if_needed(R3_RET, crc); // Updated crc is function result. No copying required (R3_ARG1 == R3_RET).
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2015 SAP SE. All rights reserved.
|
||||
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2016 SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -53,7 +53,7 @@ void VM_Version::initialize() {
|
|||
|
||||
// If PowerArchitecturePPC64 hasn't been specified explicitly determine from features.
|
||||
if (FLAG_IS_DEFAULT(PowerArchitecturePPC64)) {
|
||||
if (VM_Version::has_tcheck() && VM_Version::has_lqarx()) {
|
||||
if (VM_Version::has_lqarx()) {
|
||||
FLAG_SET_ERGO(uintx, PowerArchitecturePPC64, 8);
|
||||
} else if (VM_Version::has_popcntw()) {
|
||||
FLAG_SET_ERGO(uintx, PowerArchitecturePPC64, 7);
|
||||
|
@ -68,8 +68,7 @@ void VM_Version::initialize() {
|
|||
|
||||
bool PowerArchitecturePPC64_ok = false;
|
||||
switch (PowerArchitecturePPC64) {
|
||||
case 8: if (!VM_Version::has_tcheck() ) break;
|
||||
if (!VM_Version::has_lqarx() ) break;
|
||||
case 8: if (!VM_Version::has_lqarx() ) break;
|
||||
case 7: if (!VM_Version::has_popcntw()) break;
|
||||
case 6: if (!VM_Version::has_cmpb() ) break;
|
||||
case 5: if (!VM_Version::has_popcntb()) break;
|
||||
|
@ -80,7 +79,7 @@ void VM_Version::initialize() {
|
|||
UINTX_FORMAT " on this machine", PowerArchitecturePPC64);
|
||||
|
||||
// Power 8: Configure Data Stream Control Register.
|
||||
if (PowerArchitecturePPC64 >= 8) {
|
||||
if (has_mfdscr()) {
|
||||
config_dscr();
|
||||
}
|
||||
|
||||
|
@ -112,7 +111,7 @@ void VM_Version::initialize() {
|
|||
// Create and print feature-string.
|
||||
char buf[(num_features+1) * 16]; // Max 16 chars per feature.
|
||||
jio_snprintf(buf, sizeof(buf),
|
||||
"ppc64%s%s%s%s%s%s%s%s%s%s%s%s",
|
||||
"ppc64%s%s%s%s%s%s%s%s%s%s%s%s%s",
|
||||
(has_fsqrt() ? " fsqrt" : ""),
|
||||
(has_isel() ? " isel" : ""),
|
||||
(has_lxarxeh() ? " lxarxeh" : ""),
|
||||
|
@ -125,7 +124,8 @@ void VM_Version::initialize() {
|
|||
(has_lqarx() ? " lqarx" : ""),
|
||||
(has_vcipher() ? " vcipher" : ""),
|
||||
(has_vpmsumb() ? " vpmsumb" : ""),
|
||||
(has_tcheck() ? " tcheck" : "")
|
||||
(has_tcheck() ? " tcheck" : ""),
|
||||
(has_mfdscr() ? " mfdscr" : "")
|
||||
// Make sure number of %s matches num_features!
|
||||
);
|
||||
_features_string = os::strdup(buf);
|
||||
|
@ -610,6 +610,7 @@ void VM_Version::determine_features() {
|
|||
a->vcipher(VR0, VR1, VR2); // code[10] -> vcipher
|
||||
a->vpmsumb(VR0, VR1, VR2); // code[11] -> vpmsumb
|
||||
a->tcheck(0); // code[12] -> tcheck
|
||||
a->mfdscr(R0); // code[13] -> mfdscr
|
||||
a->blr();
|
||||
|
||||
// Emit function to set one cache line to zero. Emit function descriptor and get pointer to it.
|
||||
|
@ -657,6 +658,7 @@ void VM_Version::determine_features() {
|
|||
if (code[feature_cntr++]) features |= vcipher_m;
|
||||
if (code[feature_cntr++]) features |= vpmsumb_m;
|
||||
if (code[feature_cntr++]) features |= tcheck_m;
|
||||
if (code[feature_cntr++]) features |= mfdscr_m;
|
||||
|
||||
// Print the detection code.
|
||||
if (PrintAssembly) {
|
||||
|
@ -670,8 +672,6 @@ void VM_Version::determine_features() {
|
|||
|
||||
// Power 8: Configure Data Stream Control Register.
|
||||
void VM_Version::config_dscr() {
|
||||
assert(has_tcheck(), "Only execute on Power 8 or later!");
|
||||
|
||||
// 7 InstWords for each call (function descriptor + blr instruction).
|
||||
const int code_size = (2+2*7)*BytesPerInstWord;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2015 SAP SE. All rights reserved.
|
||||
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2016 SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -45,6 +45,7 @@ protected:
|
|||
vcipher,
|
||||
vpmsumb,
|
||||
tcheck,
|
||||
mfdscr,
|
||||
num_features // last entry to count features
|
||||
};
|
||||
enum Feature_Flag_Set {
|
||||
|
@ -62,6 +63,7 @@ protected:
|
|||
vcipher_m = (1 << vcipher),
|
||||
vpmsumb_m = (1 << vpmsumb),
|
||||
tcheck_m = (1 << tcheck ),
|
||||
mfdscr_m = (1 << mfdscr ),
|
||||
all_features_m = (unsigned long)-1
|
||||
};
|
||||
|
||||
|
@ -94,6 +96,7 @@ public:
|
|||
static bool has_vcipher() { return (_features & vcipher_m) != 0; }
|
||||
static bool has_vpmsumb() { return (_features & vpmsumb_m) != 0; }
|
||||
static bool has_tcheck() { return (_features & tcheck_m) != 0; }
|
||||
static bool has_mfdscr() { return (_features & mfdscr_m) != 0; }
|
||||
|
||||
// Assembler testing
|
||||
static void allow_all();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue