From ed72d8cee6d73aac2d0000e19ea3878db2aeb759 Mon Sep 17 00:00:00 2001 From: Eric Liu Date: Mon, 3 Feb 2020 01:47:40 +0000 Subject: [PATCH] AArch64: Merge shift pair and integral narrow into add/sub This patch implements two types of match rules like C2. 1. Merge shift pair into add/sub. 2. Merge integral narrow into add/sub. E.g. Below code is generated for `x + (((y << 56) >> 56) << 3)` lsl x0, x3, #56 asr x0, x0, #56 add x0, x2, x0, lsl #3 After this patch, generated assembly above can be optimized to below: add x0, x2, w3, sxtb #3 The test cases in this patch can show more details about those match rules. Change-Id: I82502186c8e9745dc07c349c3f66eae573006165 --- .../aarch64/test/TestProtectedAssembler.java | 4 +- .../asm/aarch64/AArch64Assembler.java | 2 +- .../aarch64/test/AArch64ArrayAddressTest.java | 8 +- .../AArch64MergeExtendWithAddSubTest.java | 238 +++++++++++++ .../AArch64MergeNarrowWithAddSubTest.java | 314 ++++++++++++++++++ .../core/aarch64/AArch64NodeMatchRules.java | 122 ++++++- .../lir/aarch64/AArch64ArithmeticOp.java | 21 +- 7 files changed, 695 insertions(+), 14 deletions(-) create mode 100644 compiler/src/org.graalvm.compiler.core.aarch64.test/src/org/graalvm/compiler/core/aarch64/test/AArch64MergeExtendWithAddSubTest.java create mode 100644 compiler/src/org.graalvm.compiler.core.aarch64.test/src/org/graalvm/compiler/core/aarch64/test/AArch64MergeNarrowWithAddSubTest.java diff --git a/compiler/src/org.graalvm.compiler.asm.aarch64.test/src/org/graalvm/compiler/asm/aarch64/test/TestProtectedAssembler.java b/compiler/src/org.graalvm.compiler.asm.aarch64.test/src/org/graalvm/compiler/asm/aarch64/test/TestProtectedAssembler.java index 2664154720318..a8a5a74e1d27e 100644 --- a/compiler/src/org.graalvm.compiler.asm.aarch64.test/src/org/graalvm/compiler/asm/aarch64/test/TestProtectedAssembler.java +++ b/compiler/src/org.graalvm.compiler.asm.aarch64.test/src/org/graalvm/compiler/asm/aarch64/test/TestProtectedAssembler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -258,7 +258,7 @@ protected void adds(int size, Register dst, Register src1, Register src2, Extend } @Override - protected void sub(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) { + public void sub(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) { super.sub(size, dst, src1, src2, extendType, shiftAmt); } diff --git a/compiler/src/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64Assembler.java b/compiler/src/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64Assembler.java index ed9e7492e9151..20e487e34ae58 100755 --- a/compiler/src/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64Assembler.java +++ b/compiler/src/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64Assembler.java @@ -1992,7 +1992,7 @@ protected void adds(int size, Register dst, Register src1, Register src2, Extend * @param extendType defines how src2 is extended to the same size as src1. * @param shiftAmt must be in range 0 to 4. */ - protected void sub(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) { + public void sub(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) { assert !dst.equals(zr); assert !src1.equals(zr); assert !src2.equals(sp); diff --git a/compiler/src/org.graalvm.compiler.core.aarch64.test/src/org/graalvm/compiler/core/aarch64/test/AArch64ArrayAddressTest.java b/compiler/src/org.graalvm.compiler.core.aarch64.test/src/org/graalvm/compiler/core/aarch64/test/AArch64ArrayAddressTest.java index e65e13454fbcc..a0f1b6b557c00 100644 --- a/compiler/src/org.graalvm.compiler.core.aarch64.test/src/org/graalvm/compiler/core/aarch64/test/AArch64ArrayAddressTest.java +++ b/compiler/src/org.graalvm.compiler.core.aarch64.test/src/org/graalvm/compiler/core/aarch64/test/AArch64ArrayAddressTest.java @@ -1,6 +1,6 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2019, Arm Limited. All rights reserved. + * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 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 @@ -27,7 +27,7 @@ import org.graalvm.compiler.api.directives.GraalDirectives; import org.graalvm.compiler.lir.LIRInstruction; -import org.graalvm.compiler.lir.aarch64.AArch64ArithmeticOp.ExtendedAddShiftOp; +import org.graalvm.compiler.lir.aarch64.AArch64ArithmeticOp.ExtendedAddSubShiftOp; import org.junit.Test; import java.util.ArrayDeque; @@ -36,7 +36,7 @@ import java.util.function.Predicate; public class AArch64ArrayAddressTest extends AArch64MatchRuleTest { - private static final Predicate predicate = op -> (op instanceof ExtendedAddShiftOp); + private static final Predicate predicate = op -> (op instanceof ExtendedAddSubShiftOp); public static byte loadByte(byte[] arr, int n) { return arr[n]; diff --git a/compiler/src/org.graalvm.compiler.core.aarch64.test/src/org/graalvm/compiler/core/aarch64/test/AArch64MergeExtendWithAddSubTest.java b/compiler/src/org.graalvm.compiler.core.aarch64.test/src/org/graalvm/compiler/core/aarch64/test/AArch64MergeExtendWithAddSubTest.java new file mode 100644 index 0000000000000..0e7f9909b431b --- /dev/null +++ b/compiler/src/org.graalvm.compiler.core.aarch64.test/src/org/graalvm/compiler/core/aarch64/test/AArch64MergeExtendWithAddSubTest.java @@ -0,0 +1,238 @@ +/* + * 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. 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. + */ +package org.graalvm.compiler.core.aarch64.test; + +import org.graalvm.compiler.lir.LIRInstruction; +import org.graalvm.compiler.lir.aarch64.AArch64ArithmeticOp; +import org.junit.Test; + +import java.util.function.Predicate; + +public class AArch64MergeExtendWithAddSubTest extends AArch64MatchRuleTest { + + private static final Predicate PRED_EXTEND_ADD_SHIFT = op -> (op instanceof AArch64ArithmeticOp.ExtendedAddSubShiftOp && op.name().equals("ADD")); + private static final Predicate PRED_EXTEND_SUB_SHIFT = op -> (op instanceof AArch64ArithmeticOp.ExtendedAddSubShiftOp && op.name().equals("SUB")); + + private static final Long[] LONG_VALUES = {-1L, 0L, 0x1234567812345678L, 0xFFFFFFFFL, 0x12L, 0x1234L, Long.MIN_VALUE, Long.MAX_VALUE}; + private static final Integer[] INT_VALUES = {-1, 0, 0x1234, 0x12345678, Integer.MIN_VALUE, Integer.MAX_VALUE}; + + private void predicateExist(String[] testCases, T[] values, Predicate predicate) { + for (String t : testCases) { + for (T value : values) { + test(t, value, value); + checkLIR(t, predicate, 1); + } + } + } + + public long addI2LShift(long x, long y) { + int z = (int) y; + return x + (z << 3); + } + + public long addB2LShift(long x, long y) { + byte z = (byte) y; + return x + (z << 2); + } + + public long addC2LShift(long x, long y) { + char z = (char) y; + return x + (z << 1); + } + + public long addS2LShift(long x, long y) { + short z = (short) y; + return x + (z << 4); + } + + public long subI2LShift(long x, long y) { + int z = (int) y; + return x - (z << 1); + } + + public long subB2LShift(long x, long y) { + byte z = (byte) y; + return x - (z << 2); + } + + public long subC2LShift(long x, long y) { + char z = (char) y; + return x - (z << 3); + } + + public long subS2LShift(long x, long y) { + short z = (short) y; + return x - (z << 4); + } + + public long addI2L(long x, long y) { + int z = (int) y; + return x + z; + } + + public long addB2L(long x, long y) { + byte z = (byte) y; + return x + z; + } + + public long addC2L(long x, long y) { + char z = (char) y; + return x + z; + } + + public long addS2L(long x, long y) { + short z = (short) y; + return x + z; + } + + public int addB2S(int x, int y) { + short a = (short) x; + byte b = (byte) y; + return a + b; + } + + public int addB2SShift(int x, int y) { + short a = (short) x; + byte b = (byte) y; + return a + (b << 2); + } + + public int addB2I(int x, int y) { + byte z = (byte) y; + return x + z; + } + + public int addB2IShift(int x, int y) { + byte z = (byte) y; + return x + (z << 3); + } + + public int addS2I(int x, int y) { + short z = (short) y; + return x + z; + } + + public int addS2IShift(int x, int y) { + short z = (short) y; + return x + (z << 2); + } + + public int addC2I(int x, int y) { + char z = (char) y; + return x + z; + } + + public int addC2IShift(int x, int y) { + char z = (char) y; + return x + (z << 1); + } + + @Test + public void mergeSignExtendIntoAdd() { + predicateExist(new String[]{"addB2S", "addB2I", "addS2I", "addC2I"}, INT_VALUES, PRED_EXTEND_ADD_SHIFT); + predicateExist(new String[]{"addB2L", "addC2L", "addI2L", "addS2L"}, LONG_VALUES, PRED_EXTEND_ADD_SHIFT); + } + + @Test + public void mergeSignExtendShiftIntoAdd() { + predicateExist(new String[]{"addB2SShift", "addB2IShift", "addS2IShift", "addC2IShift"}, INT_VALUES, PRED_EXTEND_ADD_SHIFT); + predicateExist(new String[]{"addB2LShift", "addC2LShift", "addI2LShift", "addS2LShift"}, LONG_VALUES, PRED_EXTEND_ADD_SHIFT); + } + + public long subI2L(long x, long y) { + int z = (int) y; + return x - z; + } + + public long subB2L(long x, long y) { + byte z = (byte) y; + return x - z; + } + + public long subC2L(long x, long y) { + char z = (char) y; + return x - z; + } + + public long subS2L(long x, long y) { + short z = (short) y; + return x - z; + } + + public int subB2S(int x, int y) { + short a = (short) x; + byte b = (byte) y; + return a - b; + } + + public int subB2SShift(int x, int y) { + short a = (short) x; + byte b = (byte) y; + return a - (b << 2); + } + + public int subB2I(int x, int y) { + byte z = (byte) y; + return x - z; + } + + public int subB2IShift(int x, int y) { + byte z = (byte) y; + return x - (z << 3); + } + + public int subS2I(int x, int y) { + short z = (short) y; + return x - z; + } + + public int subS2IShift(int x, int y) { + short z = (short) y; + return x - (z << 2); + } + + public int subC2I(int x, int y) { + char z = (char) y; + return x - z; + } + + public int subC2IShift(int x, int y) { + char z = (char) y; + return x - (z << 1); + } + + @Test + public void mergeSignExtendShiftIntoSub() { + predicateExist(new String[]{"subB2SShift", "subB2IShift", "subS2IShift", "subC2IShift"}, INT_VALUES, PRED_EXTEND_SUB_SHIFT); + predicateExist(new String[]{"subB2LShift", "subC2LShift", "subI2LShift", "subS2LShift"}, LONG_VALUES, PRED_EXTEND_SUB_SHIFT); + } + + @Test + public void mergeSignExtendIntoSub() { + predicateExist(new String[]{"subB2S", "subB2I", "subS2I", "subC2I"}, INT_VALUES, PRED_EXTEND_SUB_SHIFT); + predicateExist(new String[]{"subB2L", "subC2L", "subI2L", "subS2L"}, LONG_VALUES, PRED_EXTEND_SUB_SHIFT); + } +} diff --git a/compiler/src/org.graalvm.compiler.core.aarch64.test/src/org/graalvm/compiler/core/aarch64/test/AArch64MergeNarrowWithAddSubTest.java b/compiler/src/org.graalvm.compiler.core.aarch64.test/src/org/graalvm/compiler/core/aarch64/test/AArch64MergeNarrowWithAddSubTest.java new file mode 100644 index 0000000000000..98ecb46bc4dc6 --- /dev/null +++ b/compiler/src/org.graalvm.compiler.core.aarch64.test/src/org/graalvm/compiler/core/aarch64/test/AArch64MergeNarrowWithAddSubTest.java @@ -0,0 +1,314 @@ +/* + * 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. 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. + */ +package org.graalvm.compiler.core.aarch64.test; + +import org.graalvm.compiler.lir.LIRInstruction; +import org.graalvm.compiler.lir.aarch64.AArch64ArithmeticOp; +import org.junit.Test; + +import java.util.function.Predicate; + +public class AArch64MergeNarrowWithAddSubTest extends AArch64MatchRuleTest { + + private static final Predicate PRED_EXTEND_ADD_SHIFT = op -> (op instanceof AArch64ArithmeticOp.ExtendedAddSubShiftOp && op.name().equals("ADD")); + private static final Predicate PRED_EXTEND_SUB_SHIFT = op -> (op instanceof AArch64ArithmeticOp.ExtendedAddSubShiftOp && op.name().equals("SUB")); + + private static final Long[] LONG_VALUES = {-1L, 0L, 0x1234567812345678L, 0xFFFFFFFFL, 0x12L, 0x1234L, Long.MIN_VALUE, Long.MAX_VALUE}; + private static final Integer[] INT_VALUES = {-1, 0, 0x1234, 0x12345678, Integer.MIN_VALUE, Integer.MAX_VALUE}; + + private void predicateExist(String[] testCases, T[] values, Predicate predicate) { + for (String t : testCases) { + for (T value : values) { + test(t, value, value); + checkLIR(t, predicate, 1); + } + } + } + + public int addIB(int x, int y) { + return x + (y & 0xff); + } + + public int addIH(int x, int y) { + return x + (y & 0xffff); + } + + public long addLB(long x, long y) { + return x + (y & 0xff); + } + + public long addLH(long x, long y) { + return x + (y & 0xffff); + } + + public long addLW(long x, long y) { + return x + (y & 0xffffffffL); + } + + @Test + public void mergeDowncastIntoAdd() { + predicateExist(new String[]{"addIB", "addIH"}, INT_VALUES, PRED_EXTEND_ADD_SHIFT); + predicateExist(new String[]{"addLB", "addLH", "addLW"}, LONG_VALUES, PRED_EXTEND_ADD_SHIFT); + } + + public int subIB(int x, int y) { + return x - (y & 0xff); + } + + public int subIH(int x, int y) { + return x - (y & 0xffff); + } + + public long subLB(long x, long y) { + return x - (y & 0xff); + } + + public long subLH(long x, long y) { + return x - (y & 0xffff); + } + + public long subLW(long x, long y) { + return x - (y & 0xffffffffL); + } + + @Test + public void mergeDowncastIntoSub() { + predicateExist(new String[]{"subIB", "subIH"}, INT_VALUES, PRED_EXTEND_SUB_SHIFT); + predicateExist(new String[]{"subLB", "subLH", "subLW"}, LONG_VALUES, PRED_EXTEND_SUB_SHIFT); + } + + public int addIBShift(int x, int y) { + return x + ((y & 0xff) << 3); + } + + public int addIHShift(int x, int y) { + return x + ((y & 0xffff) << 3); + } + + public long addLBShift(long x, long y) { + return x + ((y & 0xffL) << 3); + } + + public long addLHShift(long x, long y) { + return x + ((y & 0xffffL) << 3); + } + + public long addLWShift(long x, long y) { + return x + ((y & 0xffffffffL) << 3); + } + + @Test + public void mergeShiftDowncastIntoAdd() { + predicateExist(new String[]{"addIBShift", "addIHShift"}, INT_VALUES, PRED_EXTEND_ADD_SHIFT); + predicateExist(new String[]{"addLBShift", "addLHShift", "addLWShift"}, LONG_VALUES, PRED_EXTEND_ADD_SHIFT); + } + + public int subIBShift(int x, int y) { + return x - ((y & 0xff) << 3); + } + + public int subIHShift(int x, int y) { + return x - ((y & 0xffff) << 3); + } + + public long subLBShift(long x, long y) { + return x - ((y & 0xffL) << 3); + } + + public long subLHShift(long x, long y) { + return x - ((y & 0xffffL) << 3); + } + + public long subLWShift(long x, long y) { + return x - ((y & 0xffffffffL) << 3); + } + + @Test + public void mergeShiftDowncastIntoSub() { + predicateExist(new String[]{"subIBShift", "subIHShift"}, INT_VALUES, PRED_EXTEND_SUB_SHIFT); + predicateExist(new String[]{"subLBShift", "subLHShift", "subLWShift"}, LONG_VALUES, PRED_EXTEND_SUB_SHIFT); + } + + public int addIntExtractShort(int x, int y) { + return x + ((y << 16) >> 16); + } + + public int addIntExtractByte(int x, int y) { + return x + ((y << 24) >> 24); + } + + public long addLongExtractInt(long x, long y) { + return x + ((y << 32) >> 32); + } + + public long addLongExtractShort(long x, long y) { + return x + ((y << 48) >> 48); + } + + public long addLongExtractByte(long x, long y) { + return x + ((y << 56) >> 56); + } + + @Test + public void addSignExtractTest() { + predicateExist(new String[]{"addIntExtractShort", "addIntExtractByte"}, INT_VALUES, PRED_EXTEND_ADD_SHIFT); + predicateExist(new String[]{"addLongExtractInt", "addLongExtractShort", "addLongExtractByte"}, LONG_VALUES, PRED_EXTEND_ADD_SHIFT); + } + + public int addIntExtractShortByShift(int x, int y) { + return x + (((y << 16) >> 16) << 3); + } + + public int addIntExtractByteByShift(int x, int y) { + return x + (((y << 24) >> 24) << 3); + } + + public long addLongExtractIntByShift(long x, long y) { + return x + (((y << 32) >> 32) << 3); + } + + public long addLongExtractShortByShift(long x, long y) { + return x + (((y << 48) >> 48) << 3); + } + + public long addLongExtractByteByShift(long x, long y) { + return x + (((y << 56) >> 56) << 3); + } + + @Test + public void addExtractByShiftTest() { + predicateExist(new String[]{"addIntExtractShortByShift", "addIntExtractByteByShift"}, INT_VALUES, PRED_EXTEND_ADD_SHIFT); + predicateExist(new String[]{"addLongExtractIntByShift", "addLongExtractShortByShift", "addLongExtractByteByShift"}, LONG_VALUES, PRED_EXTEND_ADD_SHIFT); + } + + public int addIntUnsignedExtractByte(int x, int y) { + return x + ((y << 24) >>> 24); + } + + public long addLongUnsignedExtractByte(long x, long y) { + return x + ((y << 56) >>> 56); + } + + @Test + public void addUnsignedExtractTest() { + predicateExist(new String[]{"addIntUnsignedExtractByte"}, INT_VALUES, PRED_EXTEND_ADD_SHIFT); + predicateExist(new String[]{"addLongUnsignedExtractByte"}, LONG_VALUES, PRED_EXTEND_ADD_SHIFT); + } + + public int addIntUnsignedExtractByteByShift(int x, int y) { + return x + (((y << 24) >>> 24) << 2); + } + + public long addLongUnsignedExtractByteByShift(long x, long y) { + return x + (((y << 56) >>> 56) << 1); + } + + @Test + public void addUnsignedExtractByShiftTest() { + predicateExist(new String[]{"addIntUnsignedExtractByteByShift"}, INT_VALUES, PRED_EXTEND_ADD_SHIFT); + predicateExist(new String[]{"addLongUnsignedExtractByteByShift"}, LONG_VALUES, PRED_EXTEND_ADD_SHIFT); + } + + public int subIntExtractShort(int x, int y) { + return x - ((y << 16) >> 16); + } + + public int subIntExtractByte(int x, int y) { + return x - ((y << 24) >> 24); + } + + public long subLongExtractInt(long x, long y) { + return x - ((y << 32) >> 32); + } + + public long subLongExtractShort(long x, long y) { + return x - ((y << 48) >> 48); + } + + public long subLongExtractByte(long x, long y) { + return x - ((y << 56) >> 56); + } + + @Test + public void subExtractTest() { + predicateExist(new String[]{"subIntExtractShort", "subIntExtractByte"}, INT_VALUES, PRED_EXTEND_SUB_SHIFT); + predicateExist(new String[]{"subLongExtractInt", "subLongExtractShort", "subLongExtractByte"}, LONG_VALUES, PRED_EXTEND_SUB_SHIFT); + } + + public int subIntExtractShortByShift(int x, int y) { + return x - (((y << 16) >> 16) << 3); + } + + public int subIntExtractByteByShift(int x, int y) { + return x - (((y << 24) >> 24) << 3); + } + + public long subLongExtractIntByShift(long x, long y) { + return x - (((y << 32) >> 32) << 3); + } + + public long subLongExtractShortByShift(long x, long y) { + return x - (((y << 48) >> 48) << 3); + } + + public long subLongExtractByteByShift(long x, long y) { + return x - (((y << 56) >> 56) << 3); + } + + @Test + public void subExtractByShiftTest() { + predicateExist(new String[]{"subIntExtractShortByShift", "subIntExtractByteByShift"}, INT_VALUES, PRED_EXTEND_SUB_SHIFT); + predicateExist(new String[]{"subLongExtractIntByShift", "subLongExtractShortByShift", "subLongExtractByteByShift"}, LONG_VALUES, PRED_EXTEND_SUB_SHIFT); + } + + public int subIntUnsignedExtractByte(int x, int y) { + return x - ((y << 24) >>> 24); + } + + public long subLongUnsignedExtractByte(long x, long y) { + return x - ((y << 56) >>> 56); + } + + @Test + public void subUnsignedExtractTest() { + predicateExist(new String[]{"subIntUnsignedExtractByte"}, INT_VALUES, PRED_EXTEND_SUB_SHIFT); + predicateExist(new String[]{"subLongUnsignedExtractByte"}, LONG_VALUES, PRED_EXTEND_SUB_SHIFT); + } + + public int subIntUnsignedExtractByteByShift(int x, int y) { + return x - (((y << 24) >>> 24) << 1); + } + + public long subLongUnsignedExtractByteByShift(long x, long y) { + return x - (((y << 56) >>> 56) << 2); + } + + @Test + public void subUnsignedExtractByShiftTest() { + predicateExist(new String[]{"subIntUnsignedExtractByteByShift"}, INT_VALUES, PRED_EXTEND_SUB_SHIFT); + predicateExist(new String[]{"subLongUnsignedExtractByteByShift"}, LONG_VALUES, PRED_EXTEND_SUB_SHIFT); + } +} diff --git a/compiler/src/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64NodeMatchRules.java b/compiler/src/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64NodeMatchRules.java index af24ec66ec868..2d8db5f52a03d 100644 --- a/compiler/src/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64NodeMatchRules.java +++ b/compiler/src/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64NodeMatchRules.java @@ -141,6 +141,22 @@ private static ExtendType getZeroExtendType(int fromBits) { } } + private static ExtendType getSignExtendType(int fromBits) { + switch (fromBits) { + case Byte.SIZE: + return ExtendType.SXTB; + case Short.SIZE: + return ExtendType.SXTH; + case Integer.SIZE: + return ExtendType.SXTW; + case Long.SIZE: + return ExtendType.SXTX; + default: + GraalError.shouldNotReachHere("extended from " + fromBits + "bits is not supported!"); + return null; + } + } + private AllocatableValue moveSp(AllocatableValue value) { return getLIRGeneratorTool().moveSp(value); } @@ -190,7 +206,83 @@ private ComplexMatchResult emitBitTestAndBranch(FixedNode trueSuccessor, FixedNo } private static boolean isNarrowingLongToInt(NarrowNode narrow) { - return narrow.getInputBits() == 64 && narrow.getResultBits() == 32; + return narrow.getInputBits() == Long.SIZE && narrow.getResultBits() == Integer.SIZE; + } + + private ComplexMatchResult emitExtendedAddSubShift(BinaryNode op, ValueNode x, ValueNode y, ExtendType extType, int shiftAmt) { + assert op instanceof AddNode || op instanceof SubNode; + return builder -> { + AllocatableValue src1 = moveSp(gen.asAllocatable(operand(x))); + AllocatableValue src2 = moveSp(gen.asAllocatable(operand(y))); + Variable result = gen.newVariable(LIRKind.combine(operand(x), operand(y))); + AArch64ArithmeticOp arithmeticOp = op instanceof AddNode ? AArch64ArithmeticOp.ADD : AArch64ArithmeticOp.SUB; + gen.append(new AArch64ArithmeticOp.ExtendedAddSubShiftOp(arithmeticOp, result, src1, src2, extType, shiftAmt)); + return result; + }; + } + + @MatchRule("(Add=op x (LeftShift (SignExtend=ext y) Constant=lshift))") + @MatchRule("(Sub=op x (LeftShift (SignExtend=ext y) Constant=lshift))") + @MatchRule("(Add=op x (LeftShift (ZeroExtend=ext y) Constant=lshift))") + @MatchRule("(Sub=op x (LeftShift (ZeroExtend=ext y) Constant=lshift))") + public ComplexMatchResult mergeSignExtendByShiftIntoAddSub(BinaryNode op, UnaryNode ext, ValueNode x, ValueNode y, ConstantNode lshift) { + assert lshift.getStackKind().isNumericInteger(); + int shiftAmt = lshift.asJavaConstant().asInt(); + if (shiftAmt > 4 || shiftAmt < 0) { + return null; + } + ExtendType extType; + if (ext instanceof SignExtendNode) { + extType = getSignExtendType(((SignExtendNode) ext).getInputBits()); + } else { + extType = getZeroExtendType(((ZeroExtendNode) ext).getInputBits()); + } + return emitExtendedAddSubShift(op, x, y, extType, shiftAmt); + } + + @MatchRule("(Add=op x (LeftShift (And y Constant=constant) Constant=lshift))") + @MatchRule("(Sub=op x (LeftShift (And y Constant=constant) Constant=lshift))") + public ComplexMatchResult mergeShiftDowncastIntoAddSub(BinaryNode op, ValueNode x, ValueNode y, ConstantNode constant, ConstantNode lshift) { + assert lshift.getStackKind().isNumericInteger(); + assert constant.getStackKind().isNumericInteger(); + int shiftAmt = lshift.asJavaConstant().asInt(); + long mask = constant.asJavaConstant().asLong(); + if (shiftAmt > 4 || shiftAmt < 0) { + return null; + } + if (mask != 0xff && mask != 0xffff && mask != 0xffffffffL) { + return null; + } + ExtendType extType = getZeroExtendType(Long.toBinaryString(mask).length()); + return emitExtendedAddSubShift(op, x, y, extType, shiftAmt); + } + + @MatchRule("(Add=op x (RightShift (LeftShift y Constant=shiftConst) Constant=shiftConst))") + @MatchRule("(Sub=op x (RightShift (LeftShift y Constant=shiftConst) Constant=shiftConst))") + public ComplexMatchResult mergePairShiftIntoAddSub(BinaryNode op, ValueNode x, ValueNode y, ConstantNode shiftConst) { + assert shiftConst.getStackKind().isNumericInteger(); + int shift = shiftConst.asJavaConstant().asInt(); + if (shift != 16 && shift != 24 && shift != 32 && shift != 48 && shift != 56) { + return null; + } + int extractBits = shift >= 32 ? Long.SIZE - shift : Integer.SIZE - shift; + return emitExtendedAddSubShift(op, x, y, getSignExtendType(extractBits), 0); + } + + @MatchRule("(Add=op x (LeftShift (RightShift (LeftShift y Constant=shiftConst) Constant=shiftConst) Constant=lshift))") + @MatchRule("(Sub=op x (LeftShift (RightShift (LeftShift y Constant=shiftConst) Constant=shiftConst) Constant=lshift))") + public ComplexMatchResult mergeShiftedPairShiftIntoAddSub(BinaryNode op, ValueNode x, ValueNode y, ConstantNode shiftConst, ConstantNode lshift) { + assert shiftConst.getStackKind().isNumericInteger(); + int shift = shiftConst.asJavaConstant().asInt(); + int shiftAmt = lshift.asJavaConstant().asInt(); + if (shiftAmt > 4 || shiftAmt < 0) { + return null; + } + if (shift != 16 && shift != 24 && shift != 32 && shift != 48 && shift != 56) { + return null; + } + int extractBits = shift >= 32 ? Long.SIZE - shift : Integer.SIZE - shift; + return emitExtendedAddSubShift(op, x, y, getSignExtendType(extractBits), shiftAmt); } @MatchRule("(AArch64PointerAdd=addP base ZeroExtend)") @@ -225,7 +317,7 @@ public ComplexMatchResult extendedPointerAddShift(AArch64PointerAddNode addP) { LIRKind kind = LIRKind.combineDerived(gen.getLIRKind(addP.stamp(NodeView.DEFAULT)), baseReference, null); Variable result = gen.newVariable(kind); - gen.append(new AArch64ArithmeticOp.ExtendedAddShiftOp(result, x, moveSp(y), + gen.append(new AArch64ArithmeticOp.ExtendedAddSubShiftOp(AArch64ArithmeticOp.ADD, result, x, moveSp(y), extendType, shiftNum)); return result; }; @@ -469,6 +561,32 @@ public ComplexMatchResult elideL2IForBinary(BinaryNode binary, NarrowNode narrow resultKind, op, commutative, operand(src2), operand(src1)); } + @MatchRule("(Add=op x (And y Constant=constant))") + @MatchRule("(Sub=op x (And y Constant=constant))") + public ComplexMatchResult mergeDowncastIntoAddSub(BinaryNode op, ValueNode x, ValueNode y, ConstantNode constant) { + assert constant.getStackKind().isNumericInteger(); + long mask = constant.asJavaConstant().asLong(); + if (mask != 0xff && mask != 0xffff && mask != 0xffffffffL) { + return null; + } + ExtendType extType = getZeroExtendType(Long.toBinaryString(mask).length()); + return emitExtendedAddSubShift(op, x, y, extType, 0); + } + + @MatchRule("(Add=op x (SignExtend=ext y))") + @MatchRule("(Sub=op x (SignExtend=ext y))") + @MatchRule("(Add=op x (ZeroExtend=ext y))") + @MatchRule("(Sub=op x (ZeroExtend=ext y))") + public ComplexMatchResult mergeSignExtendIntoAddSub(BinaryNode op, UnaryNode ext, ValueNode x, ValueNode y) { + ExtendType extType; + if (ext instanceof SignExtendNode) { + extType = getSignExtendType(((SignExtendNode) ext).getInputBits()); + } else { + extType = getZeroExtendType(((ZeroExtendNode) ext).getInputBits()); + } + return emitExtendedAddSubShift(op, x, y, extType, 0); + } + @MatchRule("(Negate=unary (Narrow=narrow value))") @MatchRule("(Not=unary (Narrow=narrow value))") public ComplexMatchResult elideL2IForUnary(UnaryNode unary, NarrowNode narrow) { diff --git a/compiler/src/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ArithmeticOp.java b/compiler/src/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ArithmeticOp.java index df49a1ec1590e..9f4b0bfc52907 100644 --- a/compiler/src/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ArithmeticOp.java +++ b/compiler/src/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ArithmeticOp.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -461,8 +461,9 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { } } - public static class ExtendedAddShiftOp extends AArch64LIRInstruction { - private static final LIRInstructionClass TYPE = LIRInstructionClass.create(ExtendedAddShiftOp.class); + public static class ExtendedAddSubShiftOp extends AArch64LIRInstruction { + private static final LIRInstructionClass TYPE = LIRInstructionClass.create(ExtendedAddSubShiftOp.class); + @Opcode private final AArch64ArithmeticOp op; @Def(REG) protected AllocatableValue result; @Use(REG) protected AllocatableValue src1; @Use(REG) protected AllocatableValue src2; @@ -475,8 +476,9 @@ public static class ExtendedAddShiftOp extends AArch64LIRInstruction { * @param extendType defines how src2 is extended to the same size as src1. * @param shiftAmt must be in range 0 to 4. */ - public ExtendedAddShiftOp(AllocatableValue result, AllocatableValue src1, AllocatableValue src2, AArch64Assembler.ExtendType extendType, int shiftAmt) { + public ExtendedAddSubShiftOp(AArch64ArithmeticOp op, AllocatableValue result, AllocatableValue src1, AllocatableValue src2, AArch64Assembler.ExtendType extendType, int shiftAmt) { super(TYPE); + this.op = op; this.result = result; this.src1 = src1; this.src2 = src2; @@ -487,7 +489,16 @@ public ExtendedAddShiftOp(AllocatableValue result, AllocatableValue src1, Alloca @Override public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { int size = result.getPlatformKind().getSizeInBytes() * Byte.SIZE; - masm.add(size, asRegister(result), asRegister(src1), asRegister(src2), extendType, shiftAmt); + switch (op) { + case ADD: + masm.add(size, asRegister(result), asRegister(src1), asRegister(src2), extendType, shiftAmt); + break; + case SUB: + masm.sub(size, asRegister(result), asRegister(src1), asRegister(src2), extendType, shiftAmt); + break; + default: + throw GraalError.shouldNotReachHere(); + } } }