--- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64Address.java 2016-12-09 00:46:44.726059219 -0800 @@ -0,0 +1,359 @@ +/* + * Copyright (c) 2013, 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. + * + * 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.asm.aarch64; + +import static jdk.vm.ci.aarch64.AArch64.zr; + +import org.graalvm.compiler.asm.AbstractAddress; +import org.graalvm.compiler.asm.NumUtil; +import org.graalvm.compiler.debug.GraalError; + +import jdk.vm.ci.aarch64.AArch64; +import jdk.vm.ci.code.Register; + +/** + * Represents an address in target machine memory, specified using one of the different addressing + * modes of the AArch64 ISA. - Base register only - Base register + immediate or register with + * shifted offset - Pre-indexed: base + immediate offset are written back to base register, value + * used in instruction is base + offset - Post-indexed: base + offset (immediate or register) are + * written back to base register, value used in instruction is base only - Literal: PC + 19-bit + * signed word aligned offset + *
+ * Not all addressing modes are supported for all instructions.
+ */
+public final class AArch64Address extends AbstractAddress {
+ // Placeholder for addresses that get patched later.
+ public static final AArch64Address PLACEHOLDER = createPcLiteralAddress(0);
+
+ public enum AddressingMode {
+ /**
+ * base + uimm12 << log2(memory_transfer_size).
+ */
+ IMMEDIATE_SCALED,
+ /**
+ * base + imm9.
+ */
+ IMMEDIATE_UNSCALED,
+ /**
+ * base.
+ */
+ BASE_REGISTER_ONLY,
+ /**
+ * base + offset [<< log2(memory_transfer_size)].
+ */
+ REGISTER_OFFSET,
+ /**
+ * base + extend(offset) [<< log2(memory_transfer_size)].
+ */
+ EXTENDED_REGISTER_OFFSET,
+ /**
+ * PC + imm21 (word aligned).
+ */
+ PC_LITERAL,
+ /**
+ * address = base. base is updated to base + imm9
+ */
+ IMMEDIATE_POST_INDEXED,
+ /**
+ * address = base + imm9. base is updated to base + imm9
+ */
+ IMMEDIATE_PRE_INDEXED,
+ AddressingMode,
+ }
+
+ private final Register base;
+ private final Register offset;
+ private final int immediate;
+ /**
+ * Should register offset be scaled or not.
+ */
+ private final boolean scaled;
+ private final AArch64Assembler.ExtendType extendType;
+ private final AddressingMode addressingMode;
+
+ /**
+ * General address generation mechanism. Accepted values for all parameters depend on the
+ * addressingMode. Null is never accepted for a register, if an addressMode doesn't use a
+ * register the register has to be the zero-register. extendType has to be null for every
+ * addressingMode except EXTENDED_REGISTER_OFFSET.
+ */
+ public static AArch64Address createAddress(AddressingMode addressingMode, Register base, Register offset, int immediate, boolean isScaled, AArch64Assembler.ExtendType extendType) {
+ return new AArch64Address(base, offset, immediate, isScaled, extendType, addressingMode);
+ }
+
+ /**
+ * @param base may not be null or the zero-register.
+ * @param imm9 Signed 9-bit immediate value.
+ * @return an address specifying a post-indexed immediate address pointing to base. After
+ * ldr/str instruction, base is updated to point to base + imm9
+ */
+ public static AArch64Address createPostIndexedImmediateAddress(Register base, int imm9) {
+ return new AArch64Address(base, zr, imm9, false, null, AddressingMode.IMMEDIATE_POST_INDEXED);
+ }
+
+ /**
+ * @param base may not be null or the zero-register.
+ * @param imm9 Signed 9-bit immediate value.
+ * @return an address specifying a pre-indexed immediate address pointing to base + imm9. After
+ * ldr/str instruction, base is updated to point to base + imm9
+ */
+ public static AArch64Address createPreIndexedImmediateAddress(Register base, int imm9) {
+ return new AArch64Address(base, zr, imm9, false, null, AddressingMode.IMMEDIATE_PRE_INDEXED);
+ }
+
+ /**
+ * @param base may not be null or the zero-register.
+ * @param imm12 Unsigned 12-bit immediate value. This is scaled by the word access size. This
+ * means if this address is used to load/store a word, the immediate is shifted by 2
+ * (log2Ceil(4)).
+ * @return an address specifying a signed address of the form base + imm12 <<
+ * log2(memory_transfer_size).
+ */
+ public static AArch64Address createScaledImmediateAddress(Register base, int imm12) {
+ return new AArch64Address(base, zr, imm12, true, null, AddressingMode.IMMEDIATE_SCALED);
+ }
+
+ /**
+ * @param base may not be null or the zero-register.
+ * @param imm9 Signed 9-bit immediate value.
+ * @return an address specifying an unscaled immediate address of the form base + imm9
+ */
+ public static AArch64Address createUnscaledImmediateAddress(Register base, int imm9) {
+ return new AArch64Address(base, zr, imm9, false, null, AddressingMode.IMMEDIATE_UNSCALED);
+ }
+
+ /**
+ * @param base May not be null or the zero register.
+ * @return an address specifying the address pointed to by base.
+ */
+ public static AArch64Address createBaseRegisterOnlyAddress(Register base) {
+ return createRegisterOffsetAddress(base, zr, false);
+ }
+
+ /**
+ * @param base may not be null or the zero-register.
+ * @param offset Register specifying some offset, optionally scaled by the memory_transfer_size.
+ * May not be null or the stackpointer.
+ * @param scaled Specifies whether offset should be scaled by memory_transfer_size or not.
+ * @return an address specifying a register offset address of the form base + offset [<< log2
+ * (memory_transfer_size)]
+ */
+ public static AArch64Address createRegisterOffsetAddress(Register base, Register offset, boolean scaled) {
+ return new AArch64Address(base, offset, 0, scaled, null, AddressingMode.REGISTER_OFFSET);
+ }
+
+ /**
+ * @param base may not be null or the zero-register.
+ * @param imm7 Signed 7-bit immediate value.
+ * @return an address specifying an unscaled immediate address of the form base + imm7
+ */
+ public static AArch64Address createPairUnscaledImmediateAddress(Register base, int imm7) {
+ return new AArch64Address(base, zr, imm7, false, null, AddressingMode.IMMEDIATE_UNSCALED);
+ }
+
+ /**
+ * @param base may not be null or the zero-register.
+ * @param offset Word register specifying some offset, optionally scaled by the
+ * memory_transfer_size. May not be null or the stackpointer.
+ * @param scaled Specifies whether offset should be scaled by memory_transfer_size or not.
+ * @param extendType Describes whether register is zero- or sign-extended. May not be null.
+ * @return an address specifying an extended register offset of the form base +
+ * extendType(offset) [<< log2(memory_transfer_size)]
+ */
+ public static AArch64Address createExtendedRegisterOffsetAddress(Register base, Register offset, boolean scaled, AArch64Assembler.ExtendType extendType) {
+ return new AArch64Address(base, offset, 0, scaled, extendType, AddressingMode.EXTENDED_REGISTER_OFFSET);
+ }
+
+ /**
+ * @param imm21 Signed 21-bit offset, word aligned.
+ * @return AArch64Address specifying a PC-literal address of the form PC + offset
+ */
+ public static AArch64Address createPcLiteralAddress(int imm21) {
+ return new AArch64Address(zr, zr, imm21, false, null, AddressingMode.PC_LITERAL);
+ }
+
+ private AArch64Address(Register base, Register offset, int immediate, boolean scaled, AArch64Assembler.ExtendType extendType, AddressingMode addressingMode) {
+ this.base = base;
+ this.offset = offset;
+ if ((addressingMode == AddressingMode.REGISTER_OFFSET || addressingMode == AddressingMode.EXTENDED_REGISTER_OFFSET) && offset.equals(zr)) {
+ this.addressingMode = AddressingMode.BASE_REGISTER_ONLY;
+ } else {
+ this.addressingMode = addressingMode;
+ }
+ this.immediate = immediate;
+ this.scaled = scaled;
+ this.extendType = extendType;
+ assert verify();
+ }
+
+ private boolean verify() {
+ assert addressingMode != null;
+ assert base.getRegisterCategory().equals(AArch64.CPU);
+ assert offset.getRegisterCategory().equals(AArch64.CPU);
+
+ switch (addressingMode) {
+ case IMMEDIATE_SCALED:
+ assert !base.equals(zr);
+ assert offset.equals(zr);
+ assert extendType == null;
+ assert NumUtil.isUnsignedNbit(12, immediate);
+ break;
+ case IMMEDIATE_UNSCALED:
+ assert !base.equals(zr);
+ assert offset.equals(zr);
+ assert extendType == null;
+ assert NumUtil.isSignedNbit(9, immediate);
+ break;
+ case BASE_REGISTER_ONLY:
+ assert !base.equals(zr);
+ assert offset.equals(zr);
+ assert extendType == null;
+ assert immediate == 0;
+ break;
+ case REGISTER_OFFSET:
+ assert !base.equals(zr);
+ assert offset.getRegisterCategory().equals(AArch64.CPU);
+ assert extendType == null;
+ assert immediate == 0;
+ break;
+ case EXTENDED_REGISTER_OFFSET:
+ assert !base.equals(zr);
+ assert offset.getRegisterCategory().equals(AArch64.CPU);
+ assert (extendType == AArch64Assembler.ExtendType.SXTW || extendType == AArch64Assembler.ExtendType.UXTW);
+ assert immediate == 0;
+ break;
+ case PC_LITERAL:
+ assert base.equals(zr);
+ assert offset.equals(zr);
+ assert extendType == null;
+ assert NumUtil.isSignedNbit(21, immediate);
+ assert ((immediate & 0x3) == 0);
+ break;
+ case IMMEDIATE_POST_INDEXED:
+ case IMMEDIATE_PRE_INDEXED:
+ assert !base.equals(zr);
+ assert offset.equals(zr);
+ assert extendType == null;
+ assert NumUtil.isSignedNbit(9, immediate);
+ break;
+ default:
+ throw GraalError.shouldNotReachHere();
+ }
+
+ return true;
+ }
+
+ public Register getBase() {
+ return base;
+ }
+
+ public Register getOffset() {
+ return offset;
+ }
+
+ /**
+ * @return immediate in correct representation for the given addressing mode. For example in
+ * case of addressingMode ==IMMEDIATE_UNSCALED
the value will be returned
+ * as the 9bit signed representation.
+ */
+ public int getImmediate() {
+ switch (addressingMode) {
+ case IMMEDIATE_UNSCALED:
+ case IMMEDIATE_POST_INDEXED:
+ case IMMEDIATE_PRE_INDEXED:
+ // 9-bit signed value
+ return immediate & NumUtil.getNbitNumberInt(9);
+ case IMMEDIATE_SCALED:
+ // Unsigned value can be returned as-is.
+ return immediate;
+ case PC_LITERAL:
+ // 21-bit signed value, but lower 2 bits are always 0 and are shifted out.
+ return (immediate >> 2) & NumUtil.getNbitNumberInt(19);
+ default:
+ throw GraalError.shouldNotReachHere("Should only be called for addressing modes that use immediate values.");
+ }
+ }
+
+ /**
+ * @return Raw immediate as a 32-bit signed value.
+ */
+ public int getImmediateRaw() {
+ switch (addressingMode) {
+ case IMMEDIATE_UNSCALED:
+ case IMMEDIATE_SCALED:
+ case IMMEDIATE_POST_INDEXED:
+ case IMMEDIATE_PRE_INDEXED:
+ case PC_LITERAL:
+ return immediate;
+ default:
+ throw GraalError.shouldNotReachHere("Should only be called for addressing modes that use immediate values.");
+ }
+ }
+
+ public boolean isScaled() {
+ return scaled;
+ }
+
+ public AArch64Assembler.ExtendType getExtendType() {
+ return extendType;
+ }
+
+ public AddressingMode getAddressingMode() {
+ return addressingMode;
+ }
+
+ public String toString(int log2TransferSize) {
+ int shiftVal = scaled ? log2TransferSize : 0;
+ switch (addressingMode) {
+ case IMMEDIATE_SCALED:
+ return String.format("[X%d, %d]", base.encoding, immediate << log2TransferSize);
+ case IMMEDIATE_UNSCALED:
+ return String.format("[X%d, %d]", base.encoding, immediate);
+ case BASE_REGISTER_ONLY:
+ return String.format("[X%d]", base.encoding);
+ case EXTENDED_REGISTER_OFFSET:
+ if (shiftVal != 0) {
+ return String.format("[X%d, W%d, %s %d]", base.encoding, offset.encoding, extendType.name(), shiftVal);
+ } else {
+ return String.format("[X%d, W%d, %s]", base.encoding, offset.encoding, extendType.name());
+ }
+ case REGISTER_OFFSET:
+ if (shiftVal != 0) {
+ return String.format("[X%d, X%d, LSL %d]", base.encoding, offset.encoding, shiftVal);
+ } else {
+ // LSL 0 may be optional, but still encoded differently so we always leave it
+ // off
+ return String.format("[X%d, X%d]", base.encoding, offset.encoding);
+ }
+ case PC_LITERAL:
+ return String.format(".%s%d", immediate >= 0 ? "+" : "", immediate);
+ case IMMEDIATE_POST_INDEXED:
+ return String.format("[X%d],%d", base.encoding, immediate);
+ case IMMEDIATE_PRE_INDEXED:
+ return String.format("[X%d,%d]!", base.encoding, immediate);
+ default:
+ throw GraalError.shouldNotReachHere();
+ }
+ }
+
+}