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