diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index 233f9b6af7c14..5b516746767c1 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -5666,20 +5666,6 @@ operand indIndex(iRegP reg, iRegL lreg) %} %} -operand indOffI(iRegP reg, immIOffset off) -%{ - constraint(ALLOC_IN_RC(ptr_reg)); - match(AddP reg off); - op_cost(0); - format %{ "[$reg, $off]" %} - interface(MEMORY_INTER) %{ - base($reg); - index(0xffffffff); - scale(0x0); - disp($off); - %} -%} - operand indOffI1(iRegP reg, immIOffset1 off) %{ constraint(ALLOC_IN_RC(ptr_reg)); @@ -5750,20 +5736,6 @@ operand indOffI16(iRegP reg, immIOffset16 off) %} %} -operand indOffL(iRegP reg, immLoffset off) -%{ - constraint(ALLOC_IN_RC(ptr_reg)); - match(AddP reg off); - op_cost(0); - format %{ "[$reg, $off]" %} - interface(MEMORY_INTER) %{ - base($reg); - index(0xffffffff); - scale(0x0); - disp($off); - %} -%} - operand indOffL1(iRegP reg, immLoffset1 off) %{ constraint(ALLOC_IN_RC(ptr_reg)); @@ -5909,7 +5881,7 @@ operand indIndexN(iRegN reg, iRegL lreg) %} %} -operand indOffIN(iRegN reg, immIOffset off) +operand indOffIN1(iRegN reg, immIOffset1 off) %{ predicate(CompressedOops::shift() == 0); constraint(ALLOC_IN_RC(ptr_reg)); @@ -5924,7 +5896,7 @@ operand indOffIN(iRegN reg, immIOffset off) %} %} -operand indOffLN(iRegN reg, immLoffset off) +operand indOffLN1(iRegN reg, immLoffset1 off) %{ predicate(CompressedOops::shift() == 0); constraint(ALLOC_IN_RC(ptr_reg)); @@ -5939,6 +5911,95 @@ operand indOffLN(iRegN reg, immLoffset off) %} %} +operand indOffIN2(iRegN reg, immIOffset2 off) +%{ + predicate(CompressedOops::shift() == 0); + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP (DecodeN reg) off); + op_cost(0); + format %{ "[$reg, $off]\t# narrow" %} + interface(MEMORY_INTER) %{ + base($reg); + index(0xffffffff); + scale(0x0); + disp($off); + %} +%} + +operand indOffLN2(iRegN reg, immLoffset2 off) +%{ + predicate(CompressedOops::shift() == 0); + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP (DecodeN reg) off); + op_cost(0); + format %{ "[$reg, $off]\t# narrow" %} + interface(MEMORY_INTER) %{ + base($reg); + index(0xffffffff); + scale(0x0); + disp($off); + %} +%} + +operand indOffIN4(iRegN reg, immIOffset4 off) +%{ + predicate(CompressedOops::shift() == 0); + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP (DecodeN reg) off); + op_cost(0); + format %{ "[$reg, $off]\t# narrow" %} + interface(MEMORY_INTER) %{ + base($reg); + index(0xffffffff); + scale(0x0); + disp($off); + %} +%} + +operand indOffLN4(iRegN reg, immLoffset4 off) +%{ + predicate(CompressedOops::shift() == 0); + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP (DecodeN reg) off); + op_cost(0); + format %{ "[$reg, $off]\t# narrow" %} + interface(MEMORY_INTER) %{ + base($reg); + index(0xffffffff); + scale(0x0); + disp($off); + %} +%} + +operand indOffIN8(iRegN reg, immIOffset8 off) +%{ + predicate(CompressedOops::shift() == 0); + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP (DecodeN reg) off); + op_cost(0); + format %{ "[$reg, $off]\t# narrow" %} + interface(MEMORY_INTER) %{ + base($reg); + index(0xffffffff); + scale(0x0); + disp($off); + %} +%} + +operand indOffLN8(iRegN reg, immLoffset8 off) +%{ + predicate(CompressedOops::shift() == 0); + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP (DecodeN reg) off); + op_cost(0); + format %{ "[$reg, $off]\t# narrow" %} + interface(MEMORY_INTER) %{ + base($reg); + index(0xffffffff); + scale(0x0); + disp($off); + %} +%} // AArch64 opto stubs need to write to the pc slot in the thread anchor @@ -6189,21 +6250,22 @@ opclass vmem16(indirect, indIndex, indOffI16, indOffL16); // instruction defs. we can turn a memory op into an Address opclass memory1(indirect, indIndexScaled, indIndexScaledI2L, indIndexI2L, indIndex, indOffI1, indOffL1, - indirectN, indIndexScaledN, indIndexScaledI2LN, indIndexI2LN, indIndexN); + indirectN, indIndexScaledN, indIndexScaledI2LN, indIndexI2LN, indIndexN, indOffIN1, indOffLN1); opclass memory2(indirect, indIndexScaled, indIndexScaledI2L, indIndexI2L, indIndex, indOffI2, indOffL2, - indirectN, indIndexScaledN, indIndexScaledI2LN, indIndexI2LN, indIndexN); + indirectN, indIndexScaledN, indIndexScaledI2LN, indIndexI2LN, indIndexN, indOffIN2, indOffLN2); opclass memory4(indirect, indIndexScaled, indIndexScaledI2L, indIndexI2L, indIndex, indOffI4, indOffL4, - indirectN, indIndexScaledN, indIndexScaledI2LN, indIndexI2LN, indIndexN, indOffIN, indOffLN); + indirectN, indIndexScaledN, indIndexScaledI2LN, indIndexI2LN, indIndexN, indOffIN4, indOffLN4); opclass memory8(indirect, indIndexScaled, indIndexScaledI2L, indIndexI2L, indIndex, indOffI8, indOffL8, - indirectN, indIndexScaledN, indIndexScaledI2LN, indIndexI2LN, indIndexN, indOffIN, indOffLN); + indirectN, indIndexScaledN, indIndexScaledI2LN, indIndexI2LN, indIndexN, indOffIN8, indOffLN8); // All of the memory operands. For the pipeline description. opclass memory(indirect, indIndexScaled, indIndexScaledI2L, indIndexI2L, indIndex, indOffI1, indOffL1, indOffI2, indOffL2, indOffI4, indOffL4, indOffI8, indOffL8, - indirectN, indIndexScaledN, indIndexScaledI2LN, indIndexI2LN, indIndexN, indOffIN, indOffLN); + indirectN, indIndexScaledN, indIndexScaledI2LN, indIndexI2LN, indIndexN, + indOffIN1, indOffLN1, indOffIN2, indOffLN2, indOffIN4, indOffLN4, indOffIN8, indOffLN8); // iRegIorL2I is used for src inputs in rules for 32 bit int (I) diff --git a/test/hotspot/jtreg/compiler/c2/aarch64/TestUnalignedAccessCompressedOops.java b/test/hotspot/jtreg/compiler/c2/aarch64/TestUnalignedAccessCompressedOops.java new file mode 100644 index 0000000000000..11a260a628db0 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/aarch64/TestUnalignedAccessCompressedOops.java @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2023, 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. + */ + +package compiler.c2.aarch64; + +import jdk.internal.misc.Unsafe; +import jdk.test.lib.Asserts; + +/** + * @test TestUnalignedAccessCompressedOops + * @summary AArch64: C2 compilation hits offset_ok_for_immed: assert "c2 compiler bug". + * @bug 8319690 + * @library /test/lib + * @modules java.base/jdk.internal.misc + * @requires os.arch=="aarch64" & vm.compiler2.enabled + * @run main/othervm compiler.c2.aarch64.TestUnalignedAccessCompressedOops + * @run main/othervm -Xcomp -XX:-TieredCompilation -Xmx1g + * -XX:CompileCommand=compileonly,compiler.c2.aarch64.TestUnalignedAccessCompressedOops*:: + * compiler.c2.aarch64.TestUnalignedAccessCompressedOops + */ + +public class TestUnalignedAccessCompressedOops { + + public static final int LEN = 2040; + + static final Unsafe UNSAFE = Unsafe.getUnsafe(); + static void sink(int x) {} + + public static long lseed = 1; + public static int iseed = 2; + public static short sseed = 3; + public static byte bseed = 4; + public static long lres = lseed; + public static int ires = iseed; + public static short sres = sseed; + public static byte bres = bseed; + + public static class TestLong { + + private static final byte[] BYTES = new byte[LEN]; + private static final long rawdata = 0xbeef; + private static final long data; + + static { + sink(2); + // Signed immediate byte offset: range -256 to 255 + // Positive immediate byte offset: a multiple of 8 in the range 0 to 32760 + // Other immediate byte offsets can't be encoded in the instruction field. + + // 1030 can't be encoded as "base + offset" mode into the instruction field. + UNSAFE.putLongUnaligned(BYTES, 1030, rawdata); + lres += UNSAFE.getLongUnaligned(BYTES, 1030); + // 127 can be encoded into simm9 field. + UNSAFE.putLongUnaligned(BYTES, 127, lres); + lres += UNSAFE.getLongUnaligned(BYTES, 127); + // 1096 can be encoded into uimm12 field. + UNSAFE.putLongUnaligned(BYTES, 1096, lres); + data = UNSAFE.getLongUnaligned(BYTES, 1096); + } + + } + + public static class TestInt { + + private static final byte[] BYTES = new byte[LEN]; + private static final int rawdata = 0xbeef; + private static final int data; + static { + sink(2); + // Signed immediate byte offset: range -256 to 255 + // Positive immediate byte offset, a multiple of 4 in the range 0 to 16380 + // Other immediate byte offsets can't be encoded in the instruction field. + + // 274 can't be encoded as "base + offset" mode into the instruction field. + UNSAFE.putIntUnaligned(BYTES, 274, rawdata); + ires += UNSAFE.getIntUnaligned(BYTES, 274); + // 255 can be encoded into simm9 field. + UNSAFE.putIntUnaligned(BYTES, 255, ires); + ires += UNSAFE.getIntUnaligned(BYTES, 255); + // 528 can be encoded into uimm12 field. + UNSAFE.putIntUnaligned(BYTES, 528, ires); + data = UNSAFE.getIntUnaligned(BYTES, 528); + } + + } + + public static class TestShort { + + private static final byte[] BYTES = new byte[LEN]; + private static final short rawdata = (short)0xbeef; + private static final short data; + static { + sink(2); + // Signed immediate byte offset: range -256 to 255 + // Positive immediate byte offset: a multiple of 2 in the range 0 to 8190 + // Other immediate byte offsets can't be encoded in the instruction field. + + // 257 can't be encoded as "base + offset" mode into the instruction field. + UNSAFE.putShortUnaligned(BYTES, 257, rawdata); + sres = (short) (sres + UNSAFE.getShortUnaligned(BYTES, 257)); + // 253 can be encoded into simm9 field. + UNSAFE.putShortUnaligned(BYTES, 253, sres); + sres = (short) (sres + UNSAFE.getShortUnaligned(BYTES, 253)); + // 272 can be encoded into uimm12 field. + UNSAFE.putShortUnaligned(BYTES, 272, sres); + data = UNSAFE.getShortUnaligned(BYTES, 272); + } + + } + + public static class TestByte { + + private static final byte[] BYTES = new byte[LEN]; + private static final byte rawdata = (byte)0x3f; + private static final byte data; + static { + sink(2); + // Signed immediate byte offset: range -256 to 255 + // Positive immediate byte offset: range 0 to 4095 + // Other immediate byte offsets can't be encoded in the instruction field. + + // 272 can be encoded into simm9 field. + UNSAFE.putByte(BYTES, 272, rawdata); + bres = (byte) (bres + UNSAFE.getByte(BYTES, 272)); + // 53 can be encoded into simm9 field. + UNSAFE.putByte(BYTES, 53, bres); + bres = (byte) (bres + UNSAFE.getByte(BYTES, 53)); + // 1027 can be encoded into uimm12 field. + UNSAFE.putByte(BYTES, 1027, bres); + data = UNSAFE.getByte(BYTES, 1027); + } + + } + + static void test() { + TestLong ta = new TestLong(); + Asserts.assertEquals(ta.data, (ta.rawdata + lseed) * 2, "putUnaligned long failed!"); + + TestInt tb = new TestInt(); + Asserts.assertEquals(tb.data, (tb.rawdata + iseed) * 2, "putUnaligned int failed!"); + + TestShort tc = new TestShort(); + Asserts.assertEquals(tc.data, (short) (((short) (tc.rawdata + sseed)) * 2), "putUnaligned short failed!"); + + TestByte td = new TestByte(); + Asserts.assertEquals(td.data, (byte) (((byte) (td.rawdata + bseed)) * 2), "put byte failed!"); + } + + public static void main(String[] strArr) { + test(); + } +}