8242429: Better implementation for sign extract

Reviewed-by: vlivanov, thartmann
This commit is contained in:
Eric Liu 2020-05-12 10:19:01 +08:00 committed by Yang Zhang
parent 91220287fc
commit babaab2edb
4 changed files with 145 additions and 50 deletions

View File

@ -10574,30 +10574,6 @@ instruct divI(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2) %{
ins_pipe(idiv_reg_reg);
%}
instruct signExtract(iRegINoSp dst, iRegIorL2I src1, immI_31 div1, immI_31 div2) %{
match(Set dst (URShiftI (RShiftI src1 div1) div2));
ins_cost(INSN_COST);
format %{ "lsrw $dst, $src1, $div1" %}
ins_encode %{
__ lsrw(as_Register($dst$$reg), as_Register($src1$$reg), 31);
%}
ins_pipe(ialu_reg_shift);
%}
instruct div2Round(iRegINoSp dst, iRegIorL2I src, immI_31 div1, immI_31 div2) %{
match(Set dst (AddI src (URShiftI (RShiftI src div1) div2)));
ins_cost(INSN_COST);
format %{ "addw $dst, $src, LSR $div1" %}
ins_encode %{
__ addw(as_Register($dst$$reg),
as_Register($src$$reg),
as_Register($src$$reg),
Assembler::LSR, 31);
%}
ins_pipe(ialu_reg);
%}
// Long Divide
instruct divL(iRegLNoSp dst, iRegL src1, iRegL src2) %{
@ -10610,30 +10586,6 @@ instruct divL(iRegLNoSp dst, iRegL src1, iRegL src2) %{
ins_pipe(ldiv_reg_reg);
%}
instruct signExtractL(iRegLNoSp dst, iRegL src1, immI_63 div1, immI_63 div2) %{
match(Set dst (URShiftL (RShiftL src1 div1) div2));
ins_cost(INSN_COST);
format %{ "lsr $dst, $src1, $div1" %}
ins_encode %{
__ lsr(as_Register($dst$$reg), as_Register($src1$$reg), 63);
%}
ins_pipe(ialu_reg_shift);
%}
instruct div2RoundL(iRegLNoSp dst, iRegL src, immI_63 div1, immI_63 div2) %{
match(Set dst (AddL src (URShiftL (RShiftL src div1) div2)));
ins_cost(INSN_COST);
format %{ "add $dst, $src, $div1" %}
ins_encode %{
__ add(as_Register($dst$$reg),
as_Register($src$$reg),
as_Register($src$$reg),
Assembler::LSR, 63);
%}
ins_pipe(ialu_reg);
%}
// Integer Remainder
instruct modI(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2) %{

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2020, 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
@ -1166,6 +1166,18 @@ Node *URShiftINode::Ideal(PhaseGVN *phase, bool can_reshape) {
phase->type(shl->in(2)) == t2 )
return new AndINode( shl->in(1), phase->intcon(mask) );
// Check for (x >> n) >>> 31. Replace with (x >>> 31)
Node *shr = in(1);
if ( in1_op == Op_RShiftI ) {
Node *in11 = shr->in(1);
Node *in12 = shr->in(2);
const TypeInt *t11 = phase->type(in11)->isa_int();
const TypeInt *t12 = phase->type(in12)->isa_int();
if ( t11 && t2 && t2->is_con(31) && t12 && t12->is_con() ) {
return new URShiftINode(in11, phase->intcon(31));
}
}
return NULL;
}
@ -1295,6 +1307,17 @@ Node *URShiftLNode::Ideal(PhaseGVN *phase, bool can_reshape) {
phase->type(shl->in(2)) == t2 )
return new AndLNode( shl->in(1), phase->longcon(mask) );
// Check for (x >> n) >>> 63. Replace with (x >>> 63)
Node *shr = in(1);
if ( shr->Opcode() == Op_RShiftL ) {
Node *in11 = shr->in(1);
Node *in12 = shr->in(2);
const TypeLong *t11 = phase->type(in11)->isa_long();
const TypeInt *t12 = phase->type(in12)->isa_int();
if ( t11 && t2 && t2->is_con(63) && t12 && t12->is_con() ) {
return new URShiftLNode(in11, phase->intcon(63));
}
}
return NULL;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2020, 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
@ -252,6 +252,18 @@ Node *SubINode::Ideal(PhaseGVN *phase, bool can_reshape){
return new SubINode( add1, in2->in(1) );
}
// Convert "0-(A>>31)" into "(A>>>31)"
if ( op2 == Op_RShiftI ) {
Node *in21 = in2->in(1);
Node *in22 = in2->in(2);
const TypeInt *zero = phase->type(in1)->isa_int();
const TypeInt *t21 = phase->type(in21)->isa_int();
const TypeInt *t22 = phase->type(in22)->isa_int();
if ( t21 && t22 && zero == TypeInt::ZERO && t22->is_con(31) ) {
return new URShiftINode(in21, in22);
}
}
return NULL;
}
@ -361,6 +373,18 @@ Node *SubLNode::Ideal(PhaseGVN *phase, bool can_reshape) {
return new SubLNode( add1, in2->in(1) );
}
// Convert "0L-(A>>63)" into "(A>>>63)"
if ( op2 == Op_RShiftL ) {
Node *in21 = in2->in(1);
Node *in22 = in2->in(2);
const TypeLong *zero = phase->type(in1)->isa_long();
const TypeLong *t21 = phase->type(in21)->isa_long();
const TypeInt *t22 = phase->type(in22)->isa_int();
if ( t21 && t22 && zero == TypeLong::ZERO && t22->is_con(63) ) {
return new URShiftLNode(in21, in22);
}
}
return NULL;
}

View File

@ -0,0 +1,96 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, Arm Limited. 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.
*
* 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 8242429
* @summary Better implementation for sign extract.
*
* @run main/othervm -XX:-TieredCompilation -XX:CompileCommand=dontinline,compiler.c2.TestSignExtract::signExtract*
* compiler.c2.TestSignExtract
*/
package compiler.c2;
public class TestSignExtract {
private static final long[] LONG_VALUES = {0L, 0xFFFFFFFFL, 0x12L, -1L, -123L, -0x12L, Long.MAX_VALUE, Long.MIN_VALUE};
private static final int[] INT_VALUES = {0, 0x1234, -1, -0x12345678, Integer.MAX_VALUE, Integer.MIN_VALUE};
private static int signExtractInt1(int x) {
return (x >> 1) >>> 31;
}
private static int signExtractInt2(int x) {
return (x >> 32) >>> 31;
}
private static int signExtractInt3(int x) {
return (x >> 31) >>> 31;
}
private static int signExtractInt4(int x) {
return 0 - (x >> 31);
}
private static long signExtractLong1(long x) {
return (x >> 1) >>> 63;
}
private static long signExtractLong2(long x) {
return (x >> 54) >>> 63;
}
private static long signExtractLong3(long x) {
return (x >> 63) >>> 63;
}
private static long signExtractLong4(long x) {
return 0 - (x >> 63);
}
private static int WARMUP = 5000;
public static void main(String[] args) {
for (int i = 0; i < WARMUP; i++) {
for (int e : INT_VALUES) {
// "(A >> n) >>> 31" => "(A >>> 31)"
assert e >>> 31 == signExtractInt1(e);
assert e >>> 31 == signExtractInt2(e);
assert e >>> 31 == signExtractInt3(e);
// "0 - (A >> 31)" => "(A >>> 31)"
assert e >>> 31 == signExtractInt4(e);
}
for (long e : LONG_VALUES) {
// "(A >> n) >>> 63" => "(A >>> 63)"
assert e >>> 63 == signExtractLong1(e);
assert e >>> 63 == signExtractLong2(e);
assert e >>> 63 == signExtractLong3(e);
// "0 - (A >> 63)" => "(A >>> 63)"
assert e >>> 63 == signExtractLong4(e);
}
}
}
}