1 /* 2 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package org.graalvm.compiler.asm.aarch64; 24 25 import static jdk.vm.ci.aarch64.AArch64.zr; 26 27 import org.graalvm.compiler.asm.AbstractAddress; 28 import org.graalvm.compiler.asm.NumUtil; 29 import org.graalvm.compiler.debug.GraalError; 30 31 import jdk.vm.ci.aarch64.AArch64; 32 import jdk.vm.ci.code.Register; 33 34 /** 35 * Represents an address in target machine memory, specified using one of the different addressing 36 * modes of the AArch64 ISA. - Base register only - Base register + immediate or register with 37 * shifted offset - Pre-indexed: base + immediate offset are written back to base register, value 38 * used in instruction is base + offset - Post-indexed: base + offset (immediate or register) are 39 * written back to base register, value used in instruction is base only - Literal: PC + 19-bit 40 * signed word aligned offset 41 * <p> 42 * Not all addressing modes are supported for all instructions. 43 */ 44 public final class AArch64Address extends AbstractAddress { 45 // Placeholder for addresses that get patched later. 46 public static final AArch64Address PLACEHOLDER = createPcLiteralAddress(0); 47 48 public enum AddressingMode { 49 /** 50 * base + uimm12 << log2(memory_transfer_size). 51 */ 52 IMMEDIATE_SCALED, 53 /** 54 * base + imm9. 55 */ 56 IMMEDIATE_UNSCALED, 57 /** 58 * base. 59 */ 60 BASE_REGISTER_ONLY, 61 /** 62 * base + offset [<< log2(memory_transfer_size)]. 63 */ 64 REGISTER_OFFSET, 65 /** 66 * base + extend(offset) [<< log2(memory_transfer_size)]. 67 */ 68 EXTENDED_REGISTER_OFFSET, 69 /** 70 * PC + imm21 (word aligned). 71 */ 72 PC_LITERAL, 73 /** 74 * address = base. base is updated to base + imm9 75 */ 76 IMMEDIATE_POST_INDEXED, 77 /** 78 * address = base + imm9. base is updated to base + imm9 79 */ 80 IMMEDIATE_PRE_INDEXED, 81 AddressingMode, 82 } 83 84 private final Register base; 85 private final Register offset; 86 private final int immediate; 87 /** 88 * Should register offset be scaled or not. 89 */ 90 private final boolean scaled; 91 private final AArch64Assembler.ExtendType extendType; 92 private final AddressingMode addressingMode; 93 94 /** 95 * General address generation mechanism. Accepted values for all parameters depend on the 96 * addressingMode. Null is never accepted for a register, if an addressMode doesn't use a 97 * register the register has to be the zero-register. extendType has to be null for every 98 * addressingMode except EXTENDED_REGISTER_OFFSET. 99 */ 100 public static AArch64Address createAddress(AddressingMode addressingMode, Register base, Register offset, int immediate, boolean isScaled, AArch64Assembler.ExtendType extendType) { 101 return new AArch64Address(base, offset, immediate, isScaled, extendType, addressingMode); 102 } 103 104 /** 105 * @param base may not be null or the zero-register. 106 * @param imm9 Signed 9-bit immediate value. 107 * @return an address specifying a post-indexed immediate address pointing to base. After 108 * ldr/str instruction, base is updated to point to base + imm9 109 */ 110 public static AArch64Address createPostIndexedImmediateAddress(Register base, int imm9) { 111 return new AArch64Address(base, zr, imm9, false, null, AddressingMode.IMMEDIATE_POST_INDEXED); 112 } 113 114 /** 115 * @param base may not be null or the zero-register. 116 * @param imm9 Signed 9-bit immediate value. 117 * @return an address specifying a pre-indexed immediate address pointing to base + imm9. After 118 * ldr/str instruction, base is updated to point to base + imm9 119 */ 120 public static AArch64Address createPreIndexedImmediateAddress(Register base, int imm9) { 121 return new AArch64Address(base, zr, imm9, false, null, AddressingMode.IMMEDIATE_PRE_INDEXED); 122 } 123 124 /** 125 * @param base may not be null or the zero-register. 126 * @param imm12 Unsigned 12-bit immediate value. This is scaled by the word access size. This 127 * means if this address is used to load/store a word, the immediate is shifted by 2 128 * (log2Ceil(4)). 129 * @return an address specifying a signed address of the form base + imm12 << 130 * log2(memory_transfer_size). 131 */ 132 public static AArch64Address createScaledImmediateAddress(Register base, int imm12) { 133 return new AArch64Address(base, zr, imm12, true, null, AddressingMode.IMMEDIATE_SCALED); 134 } 135 136 /** 137 * @param base may not be null or the zero-register. 138 * @param imm9 Signed 9-bit immediate value. 139 * @return an address specifying an unscaled immediate address of the form base + imm9 140 */ 141 public static AArch64Address createUnscaledImmediateAddress(Register base, int imm9) { 142 return new AArch64Address(base, zr, imm9, false, null, AddressingMode.IMMEDIATE_UNSCALED); 143 } 144 145 /** 146 * @param base May not be null or the zero register. 147 * @return an address specifying the address pointed to by base. 148 */ 149 public static AArch64Address createBaseRegisterOnlyAddress(Register base) { 150 return createRegisterOffsetAddress(base, zr, false); 151 } 152 153 /** 154 * @param base may not be null or the zero-register. 155 * @param offset Register specifying some offset, optionally scaled by the memory_transfer_size. 156 * May not be null or the stackpointer. 157 * @param scaled Specifies whether offset should be scaled by memory_transfer_size or not. 158 * @return an address specifying a register offset address of the form base + offset [<< log2 159 * (memory_transfer_size)] 160 */ 161 public static AArch64Address createRegisterOffsetAddress(Register base, Register offset, boolean scaled) { 162 return new AArch64Address(base, offset, 0, scaled, null, AddressingMode.REGISTER_OFFSET); 163 } 164 165 /** 166 * @param base may not be null or the zero-register. 167 * @param imm7 Signed 7-bit immediate value. 168 * @return an address specifying an unscaled immediate address of the form base + imm7 169 */ 170 public static AArch64Address createPairUnscaledImmediateAddress(Register base, int imm7) { 171 return new AArch64Address(base, zr, imm7, false, null, AddressingMode.IMMEDIATE_UNSCALED); 172 } 173 174 /** 175 * @param base may not be null or the zero-register. 176 * @param offset Word register specifying some offset, optionally scaled by the 177 * memory_transfer_size. May not be null or the stackpointer. 178 * @param scaled Specifies whether offset should be scaled by memory_transfer_size or not. 179 * @param extendType Describes whether register is zero- or sign-extended. May not be null. 180 * @return an address specifying an extended register offset of the form base + 181 * extendType(offset) [<< log2(memory_transfer_size)] 182 */ 183 public static AArch64Address createExtendedRegisterOffsetAddress(Register base, Register offset, boolean scaled, AArch64Assembler.ExtendType extendType) { 184 return new AArch64Address(base, offset, 0, scaled, extendType, AddressingMode.EXTENDED_REGISTER_OFFSET); 185 } 186 187 /** 188 * @param imm21 Signed 21-bit offset, word aligned. 189 * @return AArch64Address specifying a PC-literal address of the form PC + offset 190 */ 191 public static AArch64Address createPcLiteralAddress(int imm21) { 192 return new AArch64Address(zr, zr, imm21, false, null, AddressingMode.PC_LITERAL); 193 } 194 195 private AArch64Address(Register base, Register offset, int immediate, boolean scaled, AArch64Assembler.ExtendType extendType, AddressingMode addressingMode) { 196 this.base = base; 197 this.offset = offset; 198 if ((addressingMode == AddressingMode.REGISTER_OFFSET || addressingMode == AddressingMode.EXTENDED_REGISTER_OFFSET) && offset.equals(zr)) { 199 this.addressingMode = AddressingMode.BASE_REGISTER_ONLY; 200 } else { 201 this.addressingMode = addressingMode; 202 } 203 this.immediate = immediate; 204 this.scaled = scaled; 205 this.extendType = extendType; 206 assert verify(); 207 } 208 209 private boolean verify() { 210 assert addressingMode != null; 211 assert base.getRegisterCategory().equals(AArch64.CPU); 212 assert offset.getRegisterCategory().equals(AArch64.CPU); 213 214 switch (addressingMode) { 215 case IMMEDIATE_SCALED: 216 assert !base.equals(zr); 217 assert offset.equals(zr); 218 assert extendType == null; 219 assert NumUtil.isUnsignedNbit(12, immediate); 220 break; 221 case IMMEDIATE_UNSCALED: 222 assert !base.equals(zr); 223 assert offset.equals(zr); 224 assert extendType == null; 225 assert NumUtil.isSignedNbit(9, immediate); 226 break; 227 case BASE_REGISTER_ONLY: 228 assert !base.equals(zr); 229 assert offset.equals(zr); 230 assert extendType == null; 231 assert immediate == 0; 232 break; 233 case REGISTER_OFFSET: 234 assert !base.equals(zr); 235 assert offset.getRegisterCategory().equals(AArch64.CPU); 236 assert extendType == null; 237 assert immediate == 0; 238 break; 239 case EXTENDED_REGISTER_OFFSET: 240 assert !base.equals(zr); 241 assert offset.getRegisterCategory().equals(AArch64.CPU); 242 assert (extendType == AArch64Assembler.ExtendType.SXTW || extendType == AArch64Assembler.ExtendType.UXTW); 243 assert immediate == 0; 244 break; 245 case PC_LITERAL: 246 assert base.equals(zr); 247 assert offset.equals(zr); 248 assert extendType == null; 249 assert NumUtil.isSignedNbit(21, immediate); 250 assert ((immediate & 0x3) == 0); 251 break; 252 case IMMEDIATE_POST_INDEXED: 253 case IMMEDIATE_PRE_INDEXED: 254 assert !base.equals(zr); 255 assert offset.equals(zr); 256 assert extendType == null; 257 assert NumUtil.isSignedNbit(9, immediate); 258 break; 259 default: 260 throw GraalError.shouldNotReachHere(); 261 } 262 263 return true; 264 } 265 266 public Register getBase() { 267 return base; 268 } 269 270 public Register getOffset() { 271 return offset; 272 } 273 274 /** 275 * @return immediate in correct representation for the given addressing mode. For example in 276 * case of <code>addressingMode ==IMMEDIATE_UNSCALED </code> the value will be returned 277 * as the 9bit signed representation. 278 */ 279 public int getImmediate() { 280 switch (addressingMode) { 281 case IMMEDIATE_UNSCALED: 282 case IMMEDIATE_POST_INDEXED: 283 case IMMEDIATE_PRE_INDEXED: 284 // 9-bit signed value 285 return immediate & NumUtil.getNbitNumberInt(9); 286 case IMMEDIATE_SCALED: 287 // Unsigned value can be returned as-is. 288 return immediate; 289 case PC_LITERAL: 290 // 21-bit signed value, but lower 2 bits are always 0 and are shifted out. 291 return (immediate >> 2) & NumUtil.getNbitNumberInt(19); 292 default: 293 throw GraalError.shouldNotReachHere("Should only be called for addressing modes that use immediate values."); 294 } 295 } 296 297 /** 298 * @return Raw immediate as a 32-bit signed value. 299 */ 300 public int getImmediateRaw() { 301 switch (addressingMode) { 302 case IMMEDIATE_UNSCALED: 303 case IMMEDIATE_SCALED: 304 case IMMEDIATE_POST_INDEXED: 305 case IMMEDIATE_PRE_INDEXED: 306 case PC_LITERAL: 307 return immediate; 308 default: 309 throw GraalError.shouldNotReachHere("Should only be called for addressing modes that use immediate values."); 310 } 311 } 312 313 public boolean isScaled() { 314 return scaled; 315 } 316 317 public AArch64Assembler.ExtendType getExtendType() { 318 return extendType; 319 } 320 321 public AddressingMode getAddressingMode() { 322 return addressingMode; 323 } 324 325 public String toString(int log2TransferSize) { 326 int shiftVal = scaled ? log2TransferSize : 0; 327 switch (addressingMode) { 328 case IMMEDIATE_SCALED: 329 return String.format("[X%d, %d]", base.encoding, immediate << log2TransferSize); 330 case IMMEDIATE_UNSCALED: 331 return String.format("[X%d, %d]", base.encoding, immediate); 332 case BASE_REGISTER_ONLY: 333 return String.format("[X%d]", base.encoding); 334 case EXTENDED_REGISTER_OFFSET: 335 if (shiftVal != 0) { 336 return String.format("[X%d, W%d, %s %d]", base.encoding, offset.encoding, extendType.name(), shiftVal); 337 } else { 338 return String.format("[X%d, W%d, %s]", base.encoding, offset.encoding, extendType.name()); 339 } 340 case REGISTER_OFFSET: 341 if (shiftVal != 0) { 342 return String.format("[X%d, X%d, LSL %d]", base.encoding, offset.encoding, shiftVal); 343 } else { 344 // LSL 0 may be optional, but still encoded differently so we always leave it 345 // off 346 return String.format("[X%d, X%d]", base.encoding, offset.encoding); 347 } 348 case PC_LITERAL: 349 return String.format(".%s%d", immediate >= 0 ? "+" : "", immediate); 350 case IMMEDIATE_POST_INDEXED: 351 return String.format("[X%d],%d", base.encoding, immediate); 352 case IMMEDIATE_PRE_INDEXED: 353 return String.format("[X%d,%d]!", base.encoding, immediate); 354 default: 355 throw GraalError.shouldNotReachHere(); 356 } 357 } 358 359 }