8144693: Intrinsify StringCoding.hasNegatives() on SPARC
Implemented C2 instrinsic for StringCode.hasNegatives() on SPARC. Reviewed-by: kvn, jrose, thartmann
This commit is contained in:
parent
591784c35a
commit
579f0ea8ec
@ -4666,8 +4666,109 @@ void MacroAssembler::array_equals(bool is_array_equ, Register ary1, Register ary
|
||||
bind(Ldone);
|
||||
}
|
||||
|
||||
void MacroAssembler::has_negatives(Register inp, Register size, Register result, Register t2, Register t3, Register t4, Register t5) {
|
||||
|
||||
// test for negative bytes in input string of a given size
|
||||
// result 1 if found, 0 otherwise.
|
||||
|
||||
Label Lcore, Ltail, Lreturn, Lcore_rpt;
|
||||
|
||||
assert_different_registers(inp, size, t2, t3, t4, t5, result);
|
||||
|
||||
Register i = result; // result used as integer index i until very end
|
||||
Register lmask = t2; // t2 is aliased to lmask
|
||||
|
||||
// INITIALIZATION
|
||||
// ===========================================================
|
||||
// initialize highbits mask -> lmask = 0x8080808080808080 (8B/64b)
|
||||
// compute unaligned offset -> i
|
||||
// compute core end index -> t5
|
||||
Assembler::sethi(0x80808000, t2); //! sethi macro fails to emit optimal
|
||||
add(t2, 0x80, t2);
|
||||
sllx(t2, 32, t3);
|
||||
or3(t3, t2, lmask); // 0x8080808080808080 -> lmask
|
||||
sra(size,0,size);
|
||||
andcc(inp, 0x7, i); // unaligned offset -> i
|
||||
br(Assembler::zero, true, Assembler::pn, Lcore); // starts 8B aligned?
|
||||
delayed()->add(size, -8, t5); // (annuled) core end index -> t5
|
||||
|
||||
// ===========================================================
|
||||
|
||||
// UNALIGNED HEAD
|
||||
// ===========================================================
|
||||
// * unaligned head handling: grab aligned 8B containing unaligned inp(ut)
|
||||
// * obliterate (ignore) bytes outside string by shifting off reg ends
|
||||
// * compare with bitmask, short circuit return true if one or more high
|
||||
// bits set.
|
||||
cmp(size, 0);
|
||||
br(Assembler::zero, true, Assembler::pn, Lreturn); // short-circuit?
|
||||
delayed()->mov(0,result); // annuled so i not clobbered for following
|
||||
neg(i, t4);
|
||||
add(i, size, t5);
|
||||
ldx(inp, t4, t3); // raw aligned 8B containing unaligned head -> t3
|
||||
mov(8, t4);
|
||||
sub(t4, t5, t4);
|
||||
sra(t4, 31, t5);
|
||||
andn(t4, t5, t5);
|
||||
add(i, t5, t4);
|
||||
sll(t5, 3, t5);
|
||||
sll(t4, 3, t4); // # bits to shift right, left -> t5,t4
|
||||
srlx(t3, t5, t3);
|
||||
sllx(t3, t4, t3); // bytes outside string in 8B header obliterated -> t3
|
||||
andcc(lmask, t3, G0);
|
||||
brx(Assembler::notZero, true, Assembler::pn, Lreturn); // short circuit?
|
||||
delayed()->mov(1,result); // annuled so i not clobbered for following
|
||||
add(size, -8, t5); // core end index -> t5
|
||||
mov(8, t4);
|
||||
sub(t4, i, i); // # bytes examined in unalgn head (<8) -> i
|
||||
// ===========================================================
|
||||
|
||||
// ALIGNED CORE
|
||||
// ===========================================================
|
||||
// * iterate index i over aligned 8B sections of core, comparing with
|
||||
// bitmask, short circuit return true if one or more high bits set
|
||||
// t5 contains core end index/loop limit which is the index
|
||||
// of the MSB of last (unaligned) 8B fully contained in the string.
|
||||
// inp contains address of first byte in string/array
|
||||
// lmask contains 8B high bit mask for comparison
|
||||
// i contains next index to be processed (adr. inp+i is on 8B boundary)
|
||||
bind(Lcore);
|
||||
cmp_and_br_short(i, t5, Assembler::greater, Assembler::pn, Ltail);
|
||||
bind(Lcore_rpt);
|
||||
ldx(inp, i, t3);
|
||||
andcc(t3, lmask, G0);
|
||||
brx(Assembler::notZero, true, Assembler::pn, Lreturn);
|
||||
delayed()->mov(1, result); // annuled so i not clobbered for following
|
||||
add(i, 8, i);
|
||||
cmp_and_br_short(i, t5, Assembler::lessEqual, Assembler::pn, Lcore_rpt);
|
||||
// ===========================================================
|
||||
|
||||
// ALIGNED TAIL (<8B)
|
||||
// ===========================================================
|
||||
// handle aligned tail of 7B or less as complete 8B, obliterating end of
|
||||
// string bytes by shifting them off end, compare what's left with bitmask
|
||||
// inp contains address of first byte in string/array
|
||||
// lmask contains 8B high bit mask for comparison
|
||||
// i contains next index to be processed (adr. inp+i is on 8B boundary)
|
||||
bind(Ltail);
|
||||
subcc(size, i, t4); // # of remaining bytes in string -> t4
|
||||
// return 0 if no more remaining bytes
|
||||
br(Assembler::lessEqual, true, Assembler::pn, Lreturn);
|
||||
delayed()->mov(0, result); // annuled so i not clobbered for following
|
||||
ldx(inp, i, t3); // load final 8B (aligned) containing tail -> t3
|
||||
mov(8, t5);
|
||||
sub(t5, t4, t4);
|
||||
mov(0, result); // ** i clobbered at this point
|
||||
sll(t4, 3, t4); // bits beyond end of string -> t4
|
||||
srlx(t3, t4, t3); // bytes beyond end now obliterated -> t3
|
||||
andcc(lmask, t3, G0);
|
||||
movcc(Assembler::notZero, false, xcc, 1, result);
|
||||
bind(Lreturn);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
// Use BIS for zeroing (count is in bytes).
|
||||
void MacroAssembler::bis_zeroing(Register to, Register count, Register temp, Label& Ldone) {
|
||||
assert(UseBlockZeroing && VM_Version::has_block_zeroing(), "only works with BIS zeroing");
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. 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
|
||||
@ -1392,6 +1392,11 @@ public:
|
||||
|
||||
void array_equals(bool is_array_equ, Register ary1, Register ary2,
|
||||
Register limit, Register tmp, Register result, bool is_byte);
|
||||
// test for negative bytes in input string of a given size, result 0 if none
|
||||
void has_negatives(Register inp, Register size, Register result,
|
||||
Register t2, Register t3, Register t4,
|
||||
Register t5);
|
||||
|
||||
#endif
|
||||
|
||||
// Use BIS for zeroing
|
||||
|
@ -10168,6 +10168,22 @@ instruct array_equalsC(o0RegP ary1, o1RegP ary2, g3RegI tmp1, notemp_iRegI resul
|
||||
ins_pipe(long_memory_op);
|
||||
%}
|
||||
|
||||
instruct has_negatives(o0RegP pAryR, g3RegI iSizeR, notemp_iRegI resultR,
|
||||
iRegL tmp1L, iRegL tmp2L, iRegL tmp3L, iRegL tmp4L,
|
||||
flagsReg ccr)
|
||||
%{
|
||||
match(Set resultR (HasNegatives pAryR iSizeR));
|
||||
effect(TEMP resultR, TEMP tmp1L, TEMP tmp2L, TEMP tmp3L, TEMP tmp4L, USE pAryR, USE iSizeR, KILL ccr);
|
||||
format %{ "has negatives byte[] $pAryR,$iSizeR -> $resultR // KILL $tmp1L,$tmp2L,$tmp3L,$tmp4L" %}
|
||||
ins_encode %{
|
||||
__ has_negatives($pAryR$$Register, $iSizeR$$Register,
|
||||
$resultR$$Register,
|
||||
$tmp1L$$Register, $tmp2L$$Register,
|
||||
$tmp3L$$Register, $tmp4L$$Register);
|
||||
%}
|
||||
ins_pipe(long_memory_op);
|
||||
%}
|
||||
|
||||
// char[] to byte[] compression
|
||||
instruct string_compress(o0RegP src, o1RegP dst, g3RegI len, notemp_iRegI result, iRegL tmp, flagsReg ccr) %{
|
||||
predicate(UseVIS < 3);
|
||||
|
119
hotspot/test/compiler/intrinsics/string/TestHasNegatives.java
Normal file
119
hotspot/test/compiler/intrinsics/string/TestHasNegatives.java
Normal file
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8054307
|
||||
* @summary Validates StringCoding.hasNegatives intrinsic with a small range of tests.
|
||||
* @run main/bootclasspath java.lang.TestHasNegatives
|
||||
*/
|
||||
package java.lang;
|
||||
|
||||
import java.lang.StringCoding;
|
||||
|
||||
/*
|
||||
* @summary Validates StringCoding.hasNegatives intrinsic with a small
|
||||
* range of tests. Must be run with modified bootclasspath
|
||||
* to allow existence in java.lang package.
|
||||
*/
|
||||
public class TestHasNegatives {
|
||||
|
||||
private static byte[] tBa = new byte[4096 + 16];
|
||||
|
||||
/**
|
||||
* Completely initialize the test array, preparing it for tests of the
|
||||
* StringCoding.hasNegatives method with a given array segment offset,
|
||||
* length, and number of negative bytes.
|
||||
*/
|
||||
public static void initialize(int off, int len, int neg) {
|
||||
assert (len + off <= tBa.length);
|
||||
// insert "canary" (negative) values before offset
|
||||
for (int i = 0; i < off; ++i) {
|
||||
tBa[i] = (byte) (((i + 15) & 0x7F) | 0x80);
|
||||
}
|
||||
// fill the array segment
|
||||
for (int i = off; i < len + off; ++i) {
|
||||
tBa[i] = (byte) (((i - off + 15) & 0x7F));
|
||||
}
|
||||
if (neg != 0) {
|
||||
// modify a number (neg) disparate array bytes inside
|
||||
// segment to be negative.
|
||||
int div = (neg > 1) ? (len - 1) / (neg - 1) : 0;
|
||||
int idx;
|
||||
for (int i = 0; i < neg; ++i) {
|
||||
idx = off + (len - 1) - div * i;
|
||||
tBa[idx] = (byte) (0x80 | tBa[idx]);
|
||||
}
|
||||
}
|
||||
// insert "canary" negative values after array segment
|
||||
for (int i = len + off; i < tBa.length; ++i) {
|
||||
tBa[i] = (byte) (((i + 15) & 0x7F) | 0x80);
|
||||
}
|
||||
}
|
||||
|
||||
/** Sizes of array segments to test. */
|
||||
private static int sizes[] = { 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 13, 17, 19, 23, 37, 61, 131,
|
||||
4099 };
|
||||
|
||||
/**
|
||||
* Test different array segment sizes, offsets, and number of negative
|
||||
* bytes.
|
||||
*/
|
||||
public static void test_hasNegatives() throws Exception {
|
||||
int len, off;
|
||||
int ng;
|
||||
boolean r;
|
||||
|
||||
for (ng = 0; ng < 57; ++ng) { // number of negatives in array segment
|
||||
for (off = 0; off < 8; ++off) { // starting offset of array segment
|
||||
for (int i = 0; i < sizes.length; ++i) { // array segment size
|
||||
// choice
|
||||
len = sizes[i];
|
||||
if (len + off > tBa.length)
|
||||
continue;
|
||||
initialize(off, len, ng);
|
||||
r = StringCoding.hasNegatives(tBa, off, len);
|
||||
if (r ^ ((ng == 0) ? false : true)) {
|
||||
throw new Exception("Failed test hasNegatives " + "offset: " + off + " "
|
||||
+ "length: " + len + " " + "return: " + r + " " + "negatives: "
|
||||
+ ng);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void run() throws Exception {
|
||||
// iterate to eventually get intrinsic inlined
|
||||
for (int j = 0; j < 1000; ++j) {
|
||||
test_hasNegatives();
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
(new TestHasNegatives()).run();
|
||||
System.out.println("hasNegatives validated");
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user