--- old/src/cpu/sparc/vm/macroAssembler_sparc.cpp 2016-03-07 08:35:30.291092134 +0100 +++ new/src/cpu/sparc/vm/macroAssembler_sparc.cpp 2016-03-07 08:35:30.231092132 +0100 @@ -4666,8 +4666,110 @@ 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); + sra(t4, 0, t4); + 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"); --- old/src/cpu/sparc/vm/macroAssembler_sparc.hpp 2016-03-07 08:35:30.567092142 +0100 +++ new/src/cpu/sparc/vm/macroAssembler_sparc.hpp 2016-03-07 08:35:30.507092140 +0100 @@ -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 @@ 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 --- old/src/cpu/sparc/vm/sparc.ad 2016-03-07 08:35:30.803092149 +0100 +++ new/src/cpu/sparc/vm/sparc.ad 2016-03-07 08:35:30.743092147 +0100 @@ -10171,6 +10171,22 @@ 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); --- /dev/null 2016-03-07 07:51:03.271013016 +0100 +++ new/test/compiler/intrinsics/string/TestHasNegatives.java 2016-03-07 08:35:31.035092156 +0100 @@ -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"); + } +}