1 /* 2 * Copyright (c) 2013, 2016, 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 org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.ADD; 26 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.ADDS; 27 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.ADR; 28 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.AND; 29 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.ANDS; 30 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.ASRV; 31 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.BFM; 32 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.BIC; 33 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.BICS; 34 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.BLR; 35 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.BR; 36 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.BRK; 37 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.CLREX; 38 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.CLS; 39 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.CLZ; 40 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.CSEL; 41 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.CSINC; 42 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.CSNEG; 43 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.DMB; 44 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.EON; 45 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.EOR; 46 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.EXTR; 47 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FABS; 48 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FADD; 49 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FCCMP; 50 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FCMP; 51 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FCMPZERO; 52 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FCSEL; 53 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FCVTDS; 54 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FCVTSD; 55 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FCVTZS; 56 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FDIV; 57 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FMADD; 58 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FMOV; 59 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FMSUB; 60 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FMUL; 61 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FNEG; 62 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FRINTZ; 63 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FSQRT; 64 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FSUB; 65 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.HINT; 66 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.HLT; 67 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.LDAR; 68 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.LDAXR; 69 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.LDP; 70 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.LDR; 71 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.LDRS; 72 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.LDXR; 73 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.LSLV; 74 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.LSRV; 75 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.MADD; 76 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.MOVK; 77 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.MOVN; 78 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.MOVZ; 79 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.MSUB; 80 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.ORN; 81 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.ORR; 82 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.RBIT; 83 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.RET; 84 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.REVW; 85 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.REVX; 86 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.RORV; 87 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.SBFM; 88 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.SCVTF; 89 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.SDIV; 90 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.STLR; 91 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.STLXR; 92 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.STP; 93 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.STR; 94 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.STXR; 95 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.SUB; 96 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.SUBS; 97 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.UBFM; 98 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.UDIV; 99 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.InstructionType.FP32; 100 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.InstructionType.FP64; 101 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.InstructionType.General32; 102 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.InstructionType.General64; 103 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.InstructionType.floatFromSize; 104 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.InstructionType.generalFromSize; 105 import static jdk.vm.ci.aarch64.AArch64.CPU; 106 import static jdk.vm.ci.aarch64.AArch64.SIMD; 107 import static jdk.vm.ci.aarch64.AArch64.r0; 108 import static jdk.vm.ci.aarch64.AArch64.sp; 109 import static jdk.vm.ci.aarch64.AArch64.zr; 110 111 import java.util.Arrays; 112 113 import org.graalvm.compiler.asm.Assembler; 114 import org.graalvm.compiler.asm.NumUtil; 115 import org.graalvm.compiler.asm.aarch64.AArch64Address.AddressingMode; 116 import org.graalvm.compiler.debug.GraalError; 117 118 import jdk.vm.ci.code.Register; 119 import jdk.vm.ci.code.TargetDescription; 120 121 public abstract class AArch64Assembler extends Assembler { 122 123 public static class LogicalImmediateTable { 124 125 private static final Immediate[] IMMEDIATE_TABLE = buildImmediateTable(); 126 127 private static final int ImmediateOffset = 10; 128 private static final int ImmediateRotateOffset = 16; 129 private static final int ImmediateSizeOffset = 22; 130 131 /** 132 * Specifies whether immediate can be represented in all cases (YES), as a 64bit instruction 133 * (SIXTY_FOUR_BIT_ONLY) or not at all (NO). 134 */ 135 enum Representable { 136 YES, 137 SIXTY_FOUR_BIT_ONLY, 138 NO 139 } 140 141 /** 142 * Tests whether an immediate can be encoded for logical instructions. 143 * 144 * @param is64bit if true immediate is considered a 64-bit pattern. If false we may use a 145 * 64-bit instruction to load the 32-bit pattern into a register. 146 * @return enum specifying whether immediate can be used for 32- and 64-bit logical 147 * instructions ({@code #Representable.YES}), for 64-bit instructions only ( 148 * {@link Representable#SIXTY_FOUR_BIT_ONLY}) or not at all ( 149 * {@link Representable#NO}). 150 */ 151 public static Representable isRepresentable(boolean is64bit, long immediate) { 152 int pos = getLogicalImmTablePos(is64bit, immediate); 153 if (pos < 0) { 154 // if 32bit instruction we can try again as 64bit immediate which may succeed. 155 // i.e. 0xffffffff fails as a 32bit immediate but works as 64bit one. 156 if (!is64bit) { 157 assert NumUtil.isUnsignedNbit(32, immediate); 158 pos = getLogicalImmTablePos(true, immediate); 159 return pos >= 0 ? Representable.SIXTY_FOUR_BIT_ONLY : Representable.NO; 160 } 161 return Representable.NO; 162 } 163 Immediate imm = IMMEDIATE_TABLE[pos]; 164 return imm.only64bit() ? Representable.SIXTY_FOUR_BIT_ONLY : Representable.YES; 165 } 166 167 public static Representable isRepresentable(int immediate) { 168 return isRepresentable(false, immediate & 0xFFFF_FFFFL); 169 } 170 171 public static int getLogicalImmEncoding(boolean is64bit, long value) { 172 int pos = getLogicalImmTablePos(is64bit, value); 173 assert pos >= 0 : "Value cannot be represented as logical immediate: " + value + ", is64bit=" + is64bit; 174 Immediate imm = IMMEDIATE_TABLE[pos]; 175 assert is64bit || !imm.only64bit() : "Immediate can only be represented for 64bit, but 32bit instruction specified"; 176 return IMMEDIATE_TABLE[pos].encoding; 177 } 178 179 /** 180 * @param is64bit if true also allow 64-bit only encodings to be returned. 181 * @return If positive the return value is the position into the IMMEDIATE_TABLE for the 182 * given immediate, if negative the immediate cannot be encoded. 183 */ 184 private static int getLogicalImmTablePos(boolean is64bit, long value) { 185 Immediate imm; 186 if (!is64bit) { 187 // 32bit instructions can only have 32bit immediates. 188 if (!NumUtil.isUnsignedNbit(32, value)) { 189 return -1; 190 } 191 // If we have a 32bit instruction (and therefore immediate) we have to duplicate it 192 // across 64bit to find it in the table. 193 imm = new Immediate(value << 32 | value); 194 } else { 195 imm = new Immediate(value); 196 } 197 int pos = Arrays.binarySearch(IMMEDIATE_TABLE, imm); 198 if (pos < 0) { 199 return -1; 200 } 201 if (!is64bit && IMMEDIATE_TABLE[pos].only64bit()) { 202 return -1; 203 } 204 return pos; 205 } 206 207 /** 208 * To quote 5.4.2: [..] an immediate is a 32 or 64 bit pattern viewed as a vector of 209 * identical elements of size e = 2, 4, 8, 16, 32 or (in the case of bimm64) 64 bits. Each 210 * element contains the same sub-pattern: a single run of 1 to e-1 non-zero bits, rotated by 211 * 0 to e-1 bits. It is encoded in the following: 10-16: rotation amount (6bit) starting 212 * from 1s in the LSB (i.e. 0111->1011->1101->1110) 16-22: This stores a combination of the 213 * number of set bits and the pattern size. The pattern size is encoded as follows (x is 214 * used to store the number of 1 bits - 1) e pattern 2 1111xx 4 1110xx 8 110xxx 16 10xxxx 32 215 * 0xxxxx 64 xxxxxx 22: if set we have an instruction with 64bit pattern? 216 */ 217 private static final class Immediate implements Comparable<Immediate> { 218 public final long imm; 219 public final int encoding; 220 221 Immediate(long imm, boolean is64, int s, int r) { 222 this.imm = imm; 223 this.encoding = computeEncoding(is64, s, r); 224 } 225 226 // Used to be able to binary search for an immediate in the table. 227 Immediate(long imm) { 228 this(imm, false, 0, 0); 229 } 230 231 /** 232 * Returns true if this pattern is only representable as 64bit. 233 */ 234 public boolean only64bit() { 235 return (encoding & (1 << ImmediateSizeOffset)) != 0; 236 } 237 238 private static int computeEncoding(boolean is64, int s, int r) { 239 int sf = is64 ? 1 : 0; 240 return sf << ImmediateSizeOffset | r << ImmediateRotateOffset | s << ImmediateOffset; 241 } 242 243 @Override 244 public int compareTo(Immediate o) { 245 return Long.compare(imm, o.imm); 246 } 247 } 248 249 private static Immediate[] buildImmediateTable() { 250 final int nrImmediates = 5334; 251 final Immediate[] table = new Immediate[nrImmediates]; 252 int nrImms = 0; 253 for (int logE = 1; logE <= 6; logE++) { 254 int e = 1 << logE; 255 long mask = NumUtil.getNbitNumberLong(e); 256 for (int nrOnes = 1; nrOnes < e; nrOnes++) { 257 long val = (1L << nrOnes) - 1; 258 // r specifies how much we rotate the value 259 for (int r = 0; r < e; r++) { 260 long immediate = (val >>> r | val << (e - r)) & mask; 261 // Duplicate pattern to fill whole 64bit range. 262 switch (logE) { 263 case 1: 264 immediate |= immediate << 2; 265 immediate |= immediate << 4; 266 immediate |= immediate << 8; 267 immediate |= immediate << 16; 268 immediate |= immediate << 32; 269 break; 270 case 2: 271 immediate |= immediate << 4; 272 immediate |= immediate << 8; 273 immediate |= immediate << 16; 274 immediate |= immediate << 32; 275 break; 276 case 3: 277 immediate |= immediate << 8; 278 immediate |= immediate << 16; 279 immediate |= immediate << 32; 280 break; 281 case 4: 282 immediate |= immediate << 16; 283 immediate |= immediate << 32; 284 break; 285 case 5: 286 immediate |= immediate << 32; 287 break; 288 } 289 // 5 - logE can underflow to -1, but we shift this bogus result 290 // out of the masked area. 291 int sizeEncoding = (1 << (5 - logE)) - 1; 292 int s = ((sizeEncoding << (logE + 1)) & 0x3f) | (nrOnes - 1); 293 table[nrImms++] = new Immediate(immediate, /* is64bit */e == 64, s, r); 294 } 295 } 296 } 297 Arrays.sort(table); 298 assert nrImms == nrImmediates : nrImms + " instead of " + nrImmediates + " in table."; 299 assert checkDuplicates(table) : "Duplicate values in table."; 300 return table; 301 } 302 303 private static boolean checkDuplicates(Immediate[] table) { 304 for (int i = 0; i < table.length - 1; i++) { 305 if (table[i].imm >= table[i + 1].imm) { 306 return false; 307 } 308 } 309 return true; 310 } 311 } 312 313 private static final int RdOffset = 0; 314 private static final int Rs1Offset = 5; 315 private static final int Rs2Offset = 16; 316 private static final int Rs3Offset = 10; 317 private static final int RtOffset = 0; 318 private static final int RnOffset = 5; 319 private static final int Rt2Offset = 10; 320 321 /* Helper functions */ 322 private static int rd(Register reg) { 323 return reg.encoding << RdOffset; 324 } 325 326 private static int rs1(Register reg) { 327 return reg.encoding << Rs1Offset; 328 } 329 330 private static int rs2(Register reg) { 331 return reg.encoding << Rs2Offset; 332 } 333 334 private static int rs3(Register reg) { 335 return reg.encoding << Rs3Offset; 336 } 337 338 private static int rt(Register reg) { 339 return reg.encoding << RtOffset; 340 } 341 342 private static int rt2(Register reg) { 343 return reg.encoding << Rt2Offset; 344 } 345 346 private static int rn(Register reg) { 347 return reg.encoding << RnOffset; 348 } 349 350 /** 351 * Enumeration of all different instruction kinds: General32/64 are the general instructions 352 * (integer, branch, etc.), for 32-, respectively 64-bit operands. FP32/64 is the encoding for 353 * the 32/64bit float operations 354 */ 355 protected enum InstructionType { 356 General32(0b00 << 30, 32, true), 357 General64(0b10 << 30, 64, true), 358 FP32(0x00000000, 32, false), 359 FP64(0x00400000, 64, false); 360 361 public final int encoding; 362 public final int width; 363 public final boolean isGeneral; 364 365 InstructionType(int encoding, int width, boolean isGeneral) { 366 this.encoding = encoding; 367 this.width = width; 368 this.isGeneral = isGeneral; 369 } 370 371 public static InstructionType generalFromSize(int size) { 372 assert size == 32 || size == 64; 373 return size == 32 ? General32 : General64; 374 } 375 376 public static InstructionType floatFromSize(int size) { 377 assert size == 32 || size == 64; 378 return size == 32 ? FP32 : FP64; 379 } 380 381 } 382 383 private static final int ImmediateOffset = 10; 384 private static final int ImmediateRotateOffset = 16; 385 private static final int ImmediateSizeOffset = 22; 386 private static final int ExtendTypeOffset = 13; 387 388 private static final int AddSubImmOp = 0x11000000; 389 private static final int AddSubShift12 = 0b01 << 22; 390 private static final int AddSubSetFlag = 0x20000000; 391 392 private static final int LogicalImmOp = 0x12000000; 393 394 private static final int MoveWideImmOp = 0x12800000; 395 private static final int MoveWideImmOffset = 5; 396 private static final int MoveWideShiftOffset = 21; 397 398 private static final int BitfieldImmOp = 0x13000000; 399 400 private static final int AddSubShiftedOp = 0x0B000000; 401 private static final int ShiftTypeOffset = 22; 402 403 private static final int AddSubExtendedOp = 0x0B200000; 404 405 private static final int MulOp = 0x1B000000; 406 private static final int DataProcessing1SourceOp = 0x5AC00000; 407 private static final int DataProcessing2SourceOp = 0x1AC00000; 408 409 private static final int Fp1SourceOp = 0x1E204000; 410 private static final int Fp2SourceOp = 0x1E200800; 411 private static final int Fp3SourceOp = 0x1F000000; 412 413 private static final int FpConvertOp = 0x1E200000; 414 private static final int FpImmOp = 0x1E201000; 415 private static final int FpImmOffset = 13; 416 417 private static final int FpCmpOp = 0x1E202000; 418 419 private static final int PcRelImmHiOffset = 5; 420 private static final int PcRelImmLoOffset = 29; 421 422 private static final int PcRelImmOp = 0x10000000; 423 424 private static final int UnconditionalBranchImmOp = 0x14000000; 425 private static final int UnconditionalBranchRegOp = 0xD6000000; 426 private static final int CompareBranchOp = 0x34000000; 427 428 private static final int ConditionalBranchImmOffset = 5; 429 430 private static final int ConditionalSelectOp = 0x1A800000; 431 private static final int ConditionalConditionOffset = 12; 432 433 private static final int LoadStoreScaledOp = 0b111_0_01_00 << 22; 434 private static final int LoadStoreUnscaledOp = 0b111_0_00_00 << 22; 435 436 private static final int LoadStoreRegisterOp = 0b111_0_00_00_1 << 21 | 0b10 << 10; 437 438 private static final int LoadLiteralOp = 0x18000000; 439 440 private static final int LoadStorePostIndexedOp = 0b111_0_00_00_0 << 21 | 0b01 << 10; 441 private static final int LoadStorePreIndexedOp = 0b111_0_00_00_0 << 21 | 0b11 << 10; 442 443 private static final int LoadStoreUnscaledImmOffset = 12; 444 private static final int LoadStoreScaledImmOffset = 10; 445 private static final int LoadStoreScaledRegOffset = 12; 446 private static final int LoadStoreIndexedImmOffset = 12; 447 private static final int LoadStoreTransferSizeOffset = 30; 448 private static final int LoadStoreFpFlagOffset = 26; 449 private static final int LoadLiteralImmeOffset = 5; 450 451 private static final int LoadStorePairOp = 0b101_0_010 << 23; 452 @SuppressWarnings("unused") private static final int LoadStorePairPostIndexOp = 0b101_0_001 << 23; 453 @SuppressWarnings("unused") private static final int LoadStorePairPreIndexOp = 0b101_0_011 << 23; 454 private static final int LoadStorePairImm7Offset = 15; 455 456 private static final int LogicalShiftOp = 0x0A000000; 457 458 private static final int ExceptionOp = 0xD4000000; 459 private static final int SystemImmediateOffset = 5; 460 461 @SuppressWarnings("unused") private static final int SimdImmediateOffset = 16; 462 463 private static final int BarrierOp = 0xD503301F; 464 private static final int BarrierKindOffset = 8; 465 466 /** 467 * Encoding for all instructions. 468 */ 469 public enum Instruction { 470 BCOND(0x54000000), 471 CBNZ(0x01000000), 472 CBZ(0x00000000), 473 474 B(0x00000000), 475 BL(0x80000000), 476 BR(0x001F0000), 477 BLR(0x003F0000), 478 RET(0x005F0000), 479 480 LDR(0x00000000), 481 LDRS(0x00800000), 482 LDXR(0x081f7c00), 483 LDAR(0x8dffc00), 484 LDAXR(0x85ffc00), 485 486 STR(0x00000000), 487 STXR(0x08007c00), 488 STLR(0x089ffc00), 489 STLXR(0x0800fc00), 490 491 LDP(0b1 << 22), 492 STP(0b0 << 22), 493 494 ADR(0x00000000), 495 ADRP(0x80000000), 496 497 ADD(0x00000000), 498 ADDS(ADD.encoding | AddSubSetFlag), 499 SUB(0x40000000), 500 SUBS(SUB.encoding | AddSubSetFlag), 501 502 NOT(0x00200000), 503 AND(0x00000000), 504 BIC(AND.encoding | NOT.encoding), 505 ORR(0x20000000), 506 ORN(ORR.encoding | NOT.encoding), 507 EOR(0x40000000), 508 EON(EOR.encoding | NOT.encoding), 509 ANDS(0x60000000), 510 BICS(ANDS.encoding | NOT.encoding), 511 512 ASRV(0x00002800), 513 RORV(0x00002C00), 514 LSRV(0x00002400), 515 LSLV(0x00002000), 516 517 CLS(0x00001400), 518 CLZ(0x00001000), 519 RBIT(0x00000000), 520 REVX(0x00000C00), 521 REVW(0x00000800), 522 523 MOVN(0x00000000), 524 MOVZ(0x40000000), 525 MOVK(0x60000000), 526 527 CSEL(0x00000000), 528 CSNEG(0x40000400), 529 CSINC(0x00000400), 530 531 BFM(0x20000000), 532 SBFM(0x00000000), 533 UBFM(0x40000000), 534 EXTR(0x13800000), 535 536 MADD(0x00000000), 537 MSUB(0x00008000), 538 SDIV(0x00000C00), 539 UDIV(0x00000800), 540 541 FMOV(0x00000000), 542 FMOVCPU2FPU(0x00070000), 543 FMOVFPU2CPU(0x00060000), 544 545 FCVTDS(0x00028000), 546 FCVTSD(0x00020000), 547 548 FCVTZS(0x00180000), 549 SCVTF(0x00020000), 550 551 FABS(0x00008000), 552 FSQRT(0x00018000), 553 FNEG(0x00010000), 554 555 FRINTZ(0x00058000), 556 557 FADD(0x00002000), 558 FSUB(0x00003000), 559 FMUL(0x00000000), 560 FDIV(0x00001000), 561 FMAX(0x00004000), 562 FMIN(0x00005000), 563 564 FMADD(0x00000000), 565 FMSUB(0x00008000), 566 567 FCMP(0x00000000), 568 FCMPZERO(0x00000008), 569 FCCMP(0x1E200400), 570 FCSEL(0x1E200C00), 571 572 INS(0x4e081c00), 573 UMOV(0x4e083c00), 574 575 CNT(0xe205800), 576 USRA(0x6f001400), 577 578 HLT(0x00400000), 579 BRK(0x00200000), 580 581 CLREX(0xd5033f5f), 582 HINT(0xD503201F), 583 DMB(0x000000A0), 584 585 BLR_NATIVE(0xc0000000); 586 587 public final int encoding; 588 589 Instruction(int encoding) { 590 this.encoding = encoding; 591 } 592 593 } 594 595 public enum ShiftType { 596 LSL(0), 597 LSR(1), 598 ASR(2), 599 ROR(3); 600 601 public final int encoding; 602 603 ShiftType(int encoding) { 604 this.encoding = encoding; 605 } 606 } 607 608 public enum ExtendType { 609 UXTB(0), 610 UXTH(1), 611 UXTW(2), 612 UXTX(3), 613 SXTB(4), 614 SXTH(5), 615 SXTW(6), 616 SXTX(7); 617 618 public final int encoding; 619 620 ExtendType(int encoding) { 621 this.encoding = encoding; 622 } 623 } 624 625 /** 626 * Condition Flags for branches. See 4.3 627 */ 628 public enum ConditionFlag { 629 // Integer | Floating-point meanings 630 /** Equal | Equal. */ 631 EQ(0x0), 632 633 /** Not Equal | Not equal or unordered. */ 634 NE(0x1), 635 636 /** Unsigned Higher or Same | Greater than, equal or unordered. */ 637 HS(0x2), 638 639 /** Unsigned lower | less than. */ 640 LO(0x3), 641 642 /** Minus (negative) | less than. */ 643 MI(0x4), 644 645 /** Plus (positive or zero) | greater than, equal or unordered. */ 646 PL(0x5), 647 648 /** Overflow set | unordered. */ 649 VS(0x6), 650 651 /** Overflow clear | ordered. */ 652 VC(0x7), 653 654 /** Unsigned higher | greater than or unordered. */ 655 HI(0x8), 656 657 /** Unsigned lower or same | less than or equal. */ 658 LS(0x9), 659 660 /** Signed greater than or equal | greater than or equal. */ 661 GE(0xA), 662 663 /** Signed less than | less than or unordered. */ 664 LT(0xB), 665 666 /** Signed greater than | greater than. */ 667 GT(0xC), 668 669 /** Signed less than or equal | less than, equal or unordered. */ 670 LE(0xD), 671 672 /** Always | always. */ 673 AL(0xE), 674 675 /** Always | always (identical to AL, just to have valid 0b1111 encoding). */ 676 NV(0xF); 677 678 public final int encoding; 679 680 ConditionFlag(int encoding) { 681 this.encoding = encoding; 682 } 683 684 /** 685 * @return ConditionFlag specified by decoding. 686 */ 687 public static ConditionFlag fromEncoding(int encoding) { 688 return values()[encoding]; 689 } 690 691 public ConditionFlag negate() { 692 switch (this) { 693 case EQ: 694 return NE; 695 case NE: 696 return EQ; 697 case HS: 698 return LO; 699 case LO: 700 return HS; 701 case MI: 702 return PL; 703 case PL: 704 return MI; 705 case VS: 706 return VC; 707 case VC: 708 return VS; 709 case HI: 710 return LS; 711 case LS: 712 return HI; 713 case GE: 714 return LT; 715 case LT: 716 return GE; 717 case GT: 718 return LE; 719 case LE: 720 return GT; 721 case AL: 722 case NV: 723 default: 724 throw GraalError.shouldNotReachHere(); 725 } 726 } 727 } 728 729 public AArch64Assembler(TargetDescription target) { 730 super(target); 731 } 732 733 /* Conditional Branch (5.2.1) */ 734 735 /** 736 * Branch conditionally. 737 * 738 * @param condition may not be null. 739 * @param imm21 Signed 21-bit offset, has to be word aligned. 740 */ 741 protected void b(ConditionFlag condition, int imm21) { 742 b(condition, imm21, -1); 743 } 744 745 /** 746 * Branch conditionally. Inserts instruction into code buffer at pos. 747 * 748 * @param condition may not be null. 749 * @param imm21 Signed 21-bit offset, has to be word aligned. 750 * @param pos Position at which instruction is inserted into buffer. -1 means insert at end. 751 */ 752 protected void b(ConditionFlag condition, int imm21, int pos) { 753 if (pos == -1) { 754 emitInt(Instruction.BCOND.encoding | getConditionalBranchImm(imm21) | condition.encoding); 755 } else { 756 emitInt(Instruction.BCOND.encoding | getConditionalBranchImm(imm21) | condition.encoding, pos); 757 } 758 } 759 760 /** 761 * Compare register and branch if non-zero. 762 * 763 * @param reg general purpose register. May not be null, zero-register or stackpointer. 764 * @param size Instruction size in bits. Should be either 32 or 64. 765 * @param imm21 Signed 21-bit offset, has to be word aligned. 766 */ 767 protected void cbnz(int size, Register reg, int imm21) { 768 conditionalBranchInstruction(reg, imm21, generalFromSize(size), Instruction.CBNZ, -1); 769 } 770 771 /** 772 * Compare register and branch if non-zero. 773 * 774 * @param reg general purpose register. May not be null, zero-register or stackpointer. 775 * @param size Instruction size in bits. Should be either 32 or 64. 776 * @param imm21 Signed 21-bit offset, has to be word aligned. 777 * @param pos Position at which instruction is inserted into buffer. -1 means insert at end. 778 */ 779 protected void cbnz(int size, Register reg, int imm21, int pos) { 780 conditionalBranchInstruction(reg, imm21, generalFromSize(size), Instruction.CBNZ, pos); 781 } 782 783 /** 784 * Compare and branch if zero. 785 * 786 * @param reg general purpose register. May not be null, zero-register or stackpointer. 787 * @param size Instruction size in bits. Should be either 32 or 64. 788 * @param imm21 Signed 21-bit offset, has to be word aligned. 789 */ 790 protected void cbz(int size, Register reg, int imm21) { 791 conditionalBranchInstruction(reg, imm21, generalFromSize(size), Instruction.CBZ, -1); 792 } 793 794 /** 795 * Compare register and branch if zero. 796 * 797 * @param reg general purpose register. May not be null, zero-register or stackpointer. 798 * @param size Instruction size in bits. Should be either 32 or 64. 799 * @param imm21 Signed 21-bit offset, has to be word aligned. 800 * @param pos Position at which instruction is inserted into buffer. -1 means insert at end. 801 */ 802 protected void cbz(int size, Register reg, int imm21, int pos) { 803 conditionalBranchInstruction(reg, imm21, generalFromSize(size), Instruction.CBZ, pos); 804 } 805 806 private void conditionalBranchInstruction(Register reg, int imm21, InstructionType type, Instruction instr, int pos) { 807 assert reg.getRegisterCategory().equals(CPU); 808 int instrEncoding = instr.encoding | CompareBranchOp; 809 if (pos == -1) { 810 emitInt(type.encoding | instrEncoding | getConditionalBranchImm(imm21) | rd(reg)); 811 } else { 812 emitInt(type.encoding | instrEncoding | getConditionalBranchImm(imm21) | rd(reg), pos); 813 } 814 } 815 816 private static int getConditionalBranchImm(int imm21) { 817 assert NumUtil.isSignedNbit(21, imm21) && (imm21 & 0x3) == 0 : "Immediate has to be 21bit signed number and word aligned"; 818 int imm = (imm21 & NumUtil.getNbitNumberInt(21)) >> 2; 819 return imm << ConditionalBranchImmOffset; 820 } 821 822 /* Unconditional Branch (immediate) (5.2.2) */ 823 824 /** 825 * @param imm28 Signed 28-bit offset, has to be word aligned. 826 */ 827 protected void b(int imm28) { 828 unconditionalBranchImmInstruction(imm28, Instruction.B, -1); 829 } 830 831 /** 832 * 833 * @param imm28 Signed 28-bit offset, has to be word aligned. 834 * @param pos Position where instruction is inserted into code buffer. 835 */ 836 protected void b(int imm28, int pos) { 837 unconditionalBranchImmInstruction(imm28, Instruction.B, pos); 838 } 839 840 /** 841 * Branch and link return address to register X30. 842 * 843 * @param imm28 Signed 28-bit offset, has to be word aligned. 844 */ 845 public void bl(int imm28) { 846 unconditionalBranchImmInstruction(imm28, Instruction.BL, -1); 847 } 848 849 private void unconditionalBranchImmInstruction(int imm28, Instruction instr, int pos) { 850 assert NumUtil.isSignedNbit(28, imm28) && (imm28 & 0x3) == 0 : "Immediate has to be 28bit signed number and word aligned"; 851 int imm = (imm28 & NumUtil.getNbitNumberInt(28)) >> 2; 852 int instrEncoding = instr.encoding | UnconditionalBranchImmOp; 853 if (pos == -1) { 854 emitInt(instrEncoding | imm); 855 } else { 856 emitInt(instrEncoding | imm, pos); 857 } 858 } 859 860 /* Unconditional Branch (register) (5.2.3) */ 861 862 /** 863 * Branches to address in register and writes return address into register X30. 864 * 865 * @param reg general purpose register. May not be null, zero-register or stackpointer. 866 */ 867 public void blr(Register reg) { 868 unconditionalBranchRegInstruction(BLR, reg); 869 } 870 871 /** 872 * Branches to address in register. 873 * 874 * @param reg general purpose register. May not be null, zero-register or stackpointer. 875 */ 876 protected void br(Register reg) { 877 unconditionalBranchRegInstruction(BR, reg); 878 } 879 880 /** 881 * Return to address in register. 882 * 883 * @param reg general purpose register. May not be null, zero-register or stackpointer. 884 */ 885 public void ret(Register reg) { 886 unconditionalBranchRegInstruction(RET, reg); 887 } 888 889 private void unconditionalBranchRegInstruction(Instruction instr, Register reg) { 890 assert reg.getRegisterCategory().equals(CPU); 891 assert !reg.equals(zr); 892 assert !reg.equals(sp); 893 emitInt(instr.encoding | UnconditionalBranchRegOp | rs1(reg)); 894 } 895 896 /* Load-Store Single Register (5.3.1) */ 897 898 /** 899 * Loads a srcSize value from address into rt zero-extending it. 900 * 901 * @param srcSize size of memory read in bits. Must be 8, 16, 32 or 64. 902 * @param rt general purpose register. May not be null or stackpointer. 903 * @param address all addressing modes allowed. May not be null. 904 */ 905 public void ldr(int srcSize, Register rt, AArch64Address address) { 906 assert rt.getRegisterCategory().equals(CPU); 907 assert srcSize == 8 || srcSize == 16 || srcSize == 32 || srcSize == 64; 908 int transferSize = NumUtil.log2Ceil(srcSize / 8); 909 loadStoreInstruction(LDR, rt, address, General32, transferSize); 910 } 911 912 /** 913 * Loads a srcSize value from address into rt sign-extending it. 914 * 915 * @param targetSize size of target register in bits. Must be 32 or 64. 916 * @param srcSize size of memory read in bits. Must be 8, 16 or 32, but may not be equivalent to 917 * targetSize. 918 * @param rt general purpose register. May not be null or stackpointer. 919 * @param address all addressing modes allowed. May not be null. 920 */ 921 protected void ldrs(int targetSize, int srcSize, Register rt, AArch64Address address) { 922 assert rt.getRegisterCategory().equals(CPU); 923 assert (srcSize == 8 || srcSize == 16 || srcSize == 32) && srcSize != targetSize; 924 int transferSize = NumUtil.log2Ceil(srcSize / 8); 925 loadStoreInstruction(LDRS, rt, address, generalFromSize(targetSize), transferSize); 926 } 927 928 /** 929 * Stores register rt into memory pointed by address. 930 * 931 * @param destSize number of bits written to memory. Must be 8, 16, 32 or 64. 932 * @param rt general purpose register. May not be null or stackpointer. 933 * @param address all addressing modes allowed. May not be null. 934 */ 935 public void str(int destSize, Register rt, AArch64Address address) { 936 assert rt.getRegisterCategory().equals(CPU); 937 assert destSize == 8 || destSize == 16 || destSize == 32 || destSize == 64; 938 int transferSize = NumUtil.log2Ceil(destSize / 8); 939 loadStoreInstruction(STR, rt, address, General64, transferSize); 940 } 941 942 private void loadStoreInstruction(Instruction instr, Register reg, AArch64Address address, InstructionType type, int log2TransferSize) { 943 assert log2TransferSize >= 0 && log2TransferSize < 4; 944 int transferSizeEncoding = log2TransferSize << LoadStoreTransferSizeOffset; 945 int is32Bit = type.width == 32 ? 1 << ImmediateSizeOffset : 0; 946 int isFloat = !type.isGeneral ? 1 << LoadStoreFpFlagOffset : 0; 947 int memop = instr.encoding | transferSizeEncoding | is32Bit | isFloat | rt(reg); 948 switch (address.getAddressingMode()) { 949 case IMMEDIATE_SCALED: 950 emitInt(memop | LoadStoreScaledOp | address.getImmediate() << LoadStoreScaledImmOffset | rs1(address.getBase())); 951 break; 952 case IMMEDIATE_UNSCALED: 953 emitInt(memop | LoadStoreUnscaledOp | address.getImmediate() << LoadStoreUnscaledImmOffset | rs1(address.getBase())); 954 break; 955 case BASE_REGISTER_ONLY: 956 emitInt(memop | LoadStoreScaledOp | rs1(address.getBase())); 957 break; 958 case EXTENDED_REGISTER_OFFSET: 959 case REGISTER_OFFSET: 960 ExtendType extendType = address.getAddressingMode() == AddressingMode.EXTENDED_REGISTER_OFFSET ? address.getExtendType() : ExtendType.UXTX; 961 boolean shouldScale = address.isScaled() && log2TransferSize != 0; 962 emitInt(memop | LoadStoreRegisterOp | rs2(address.getOffset()) | extendType.encoding << ExtendTypeOffset | (shouldScale ? 1 : 0) << LoadStoreScaledRegOffset | rs1(address.getBase())); 963 break; 964 case PC_LITERAL: 965 assert log2TransferSize >= 2 : "PC literal loads only works for load/stores of 32-bit and larger"; 966 transferSizeEncoding = (log2TransferSize - 2) << LoadStoreTransferSizeOffset; 967 emitInt(transferSizeEncoding | isFloat | LoadLiteralOp | rd(reg) | address.getImmediate() << LoadLiteralImmeOffset); 968 break; 969 case IMMEDIATE_POST_INDEXED: 970 emitInt(memop | LoadStorePostIndexedOp | rs1(address.getBase()) | address.getImmediate() << LoadStoreIndexedImmOffset); 971 break; 972 case IMMEDIATE_PRE_INDEXED: 973 emitInt(memop | LoadStorePreIndexedOp | rs1(address.getBase()) | address.getImmediate() << LoadStoreIndexedImmOffset); 974 break; 975 default: 976 throw GraalError.shouldNotReachHere("Unhandled addressing mode: " + address.getAddressingMode()); 977 } 978 } 979 980 /** 981 * 982 */ 983 public void ldp(int size, Register rt, Register rt2, AArch64Address address) { 984 assert size == 32 || size == 64; 985 loadStorePairInstruction(LDP, rt, rt2, address, generalFromSize(size)); 986 } 987 988 /** 989 * Store Pair of Registers calculates an address from a base register value and an immediate 990 * offset, and stores two 32-bit words or two 64-bit doublewords to the calculated address, from 991 * two registers. 992 */ 993 public void stp(int size, Register rt, Register rt2, AArch64Address address) { 994 assert size == 32 || size == 64; 995 loadStorePairInstruction(STP, rt, rt2, address, generalFromSize(size)); 996 } 997 998 private void loadStorePairInstruction(Instruction instr, Register rt, Register rt2, AArch64Address address, InstructionType type) { 999 int memop = type.encoding | instr.encoding | address.getImmediate() << LoadStorePairImm7Offset | rt2(rt2) | rn(address.getBase()) | rt(rt); 1000 switch (address.getAddressingMode()) { 1001 case IMMEDIATE_UNSCALED: 1002 emitInt(memop | LoadStorePairOp); 1003 break; 1004 default: 1005 throw GraalError.shouldNotReachHere("Unhandled addressing mode: " + address.getAddressingMode()); 1006 } 1007 } 1008 1009 /* Load-Store Exclusive (5.3.6) */ 1010 1011 /** 1012 * Load address exclusive. Natural alignment of address is required. 1013 * 1014 * @param size size of memory read in bits. Must be 8, 16, 32 or 64. 1015 * @param rt general purpose register. May not be null or stackpointer. 1016 * @param rn general purpose register. 1017 */ 1018 protected void ldxr(int size, Register rt, Register rn) { 1019 assert size == 8 || size == 16 || size == 32 || size == 64; 1020 int transferSize = NumUtil.log2Ceil(size / 8); 1021 exclusiveLoadInstruction(LDXR, rt, rn, transferSize); 1022 } 1023 1024 /** 1025 * Store address exclusive. Natural alignment of address is required. rs and rt may not point to 1026 * the same register. 1027 * 1028 * @param size size of bits written to memory. Must be 8, 16, 32 or 64. 1029 * @param rs general purpose register. Set to exclusive access status. 0 means success, 1030 * everything else failure. May not be null, or stackpointer. 1031 * @param rt general purpose register. May not be null or stackpointer. 1032 * @param rn general purpose register. 1033 */ 1034 protected void stxr(int size, Register rs, Register rt, Register rn) { 1035 assert size == 8 || size == 16 || size == 32 || size == 64; 1036 int transferSize = NumUtil.log2Ceil(size / 8); 1037 exclusiveStoreInstruction(STXR, rs, rt, rn, transferSize); 1038 } 1039 1040 /* Load-Acquire/Store-Release (5.3.7) */ 1041 1042 /* non exclusive access */ 1043 /** 1044 * Load acquire. Natural alignment of address is required. 1045 * 1046 * @param size size of memory read in bits. Must be 8, 16, 32 or 64. 1047 * @param rt general purpose register. May not be null or stackpointer. 1048 * @param rn general purpose register. 1049 */ 1050 protected void ldar(int size, Register rt, Register rn) { 1051 assert size == 8 || size == 16 || size == 32 || size == 64; 1052 int transferSize = NumUtil.log2Ceil(size / 8); 1053 exclusiveLoadInstruction(LDAR, rt, rn, transferSize); 1054 } 1055 1056 /** 1057 * Store-release. Natural alignment of address is required. 1058 * 1059 * @param size size of bits written to memory. Must be 8, 16, 32 or 64. 1060 * @param rt general purpose register. May not be null or stackpointer. 1061 * @param rn general purpose register. 1062 */ 1063 protected void stlr(int size, Register rt, Register rn) { 1064 assert size == 8 || size == 16 || size == 32 || size == 64; 1065 int transferSize = NumUtil.log2Ceil(size / 8); 1066 // Hack: Passing the zero-register means it is ignored when building the encoding. 1067 exclusiveStoreInstruction(STLR, r0, rt, rn, transferSize); 1068 } 1069 1070 /* exclusive access */ 1071 /** 1072 * Load acquire exclusive. Natural alignment of address is required. 1073 * 1074 * @param size size of memory read in bits. Must be 8, 16, 32 or 64. 1075 * @param rt general purpose register. May not be null or stackpointer. 1076 * @param rn general purpose register. 1077 */ 1078 public void ldaxr(int size, Register rt, Register rn) { 1079 assert size == 8 || size == 16 || size == 32 || size == 64; 1080 int transferSize = NumUtil.log2Ceil(size / 8); 1081 exclusiveLoadInstruction(LDAXR, rt, rn, transferSize); 1082 } 1083 1084 /** 1085 * Store-release exclusive. Natural alignment of address is required. rs and rt may not point to 1086 * the same register. 1087 * 1088 * @param size size of bits written to memory. Must be 8, 16, 32 or 64. 1089 * @param rs general purpose register. Set to exclusive access status. 0 means success, 1090 * everything else failure. May not be null, or stackpointer. 1091 * @param rt general purpose register. May not be null or stackpointer. 1092 * @param rn general purpose register. 1093 */ 1094 public void stlxr(int size, Register rs, Register rt, Register rn) { 1095 assert size == 8 || size == 16 || size == 32 || size == 64; 1096 int transferSize = NumUtil.log2Ceil(size / 8); 1097 exclusiveStoreInstruction(STLXR, rs, rt, rn, transferSize); 1098 } 1099 1100 private void exclusiveLoadInstruction(Instruction instr, Register reg, Register rn, int log2TransferSize) { 1101 assert log2TransferSize >= 0 && log2TransferSize < 4; 1102 assert reg.getRegisterCategory().equals(CPU); 1103 int transferSizeEncoding = log2TransferSize << LoadStoreTransferSizeOffset; 1104 emitInt(transferSizeEncoding | instr.encoding | 1 << ImmediateSizeOffset | rn(rn) | rt(reg)); 1105 } 1106 1107 /** 1108 * Stores data from rt into address and sets rs to the returned exclusive access status. 1109 * 1110 * @param rs general purpose register into which the exclusive access status is written. May not 1111 * be null. 1112 * @param rt general purpose register containing data to be written to memory at address. May 1113 * not be null 1114 * @param rn general purpose register containing the address specifying where rt is written to. 1115 * @param log2TransferSize log2Ceil of memory transfer size. 1116 */ 1117 private void exclusiveStoreInstruction(Instruction instr, Register rs, Register rt, Register rn, int log2TransferSize) { 1118 assert log2TransferSize >= 0 && log2TransferSize < 4; 1119 assert rt.getRegisterCategory().equals(CPU) && rs.getRegisterCategory().equals(CPU) && !rs.equals(rt); 1120 int transferSizeEncoding = log2TransferSize << LoadStoreTransferSizeOffset; 1121 emitInt(transferSizeEncoding | instr.encoding | rs2(rs) | rn(rn) | rt(rt)); 1122 } 1123 1124 /* PC-relative Address Calculation (5.4.4) */ 1125 1126 /** 1127 * Address of page: sign extends 21-bit offset, shifts if left by 12 and adds it to the value of 1128 * the PC with its bottom 12-bits cleared, writing the result to dst. 1129 * 1130 * @param dst general purpose register. May not be null, zero-register or stackpointer. 1131 * @param imm Signed 33-bit offset with lower 12bits clear. 1132 */ 1133 // protected void adrp(Register dst, long imm) { 1134 // assert (imm & NumUtil.getNbitNumberInt(12)) == 0 : "Lower 12-bit of immediate must be zero."; 1135 // assert NumUtil.isSignedNbit(33, imm); 1136 // addressCalculationInstruction(dst, (int) (imm >>> 12), Instruction.ADRP); 1137 // } 1138 1139 /** 1140 * Adds a 21-bit signed offset to the program counter and writes the result to dst. 1141 * 1142 * @param dst general purpose register. May not be null, zero-register or stackpointer. 1143 * @param imm21 Signed 21-bit offset. 1144 */ 1145 public void adr(Register dst, int imm21) { 1146 emitInt(ADR.encoding | PcRelImmOp | rd(dst) | getPcRelativeImmEncoding(imm21)); 1147 } 1148 1149 public void adr(Register dst, int imm21, int pos) { 1150 emitInt(ADR.encoding | PcRelImmOp | rd(dst) | getPcRelativeImmEncoding(imm21), pos); 1151 } 1152 1153 private static int getPcRelativeImmEncoding(int imm21) { 1154 assert NumUtil.isSignedNbit(21, imm21); 1155 int imm = imm21 & NumUtil.getNbitNumberInt(21); 1156 // higher 19 bit 1157 int immHi = (imm >> 2) << PcRelImmHiOffset; 1158 // lower 2 bit 1159 int immLo = (imm & 0x3) << PcRelImmLoOffset; 1160 return immHi | immLo; 1161 } 1162 1163 /* Arithmetic (Immediate) (5.4.1) */ 1164 1165 /** 1166 * dst = src + aimm. 1167 * 1168 * @param size register size. Has to be 32 or 64. 1169 * @param dst general purpose register. May not be null or zero-register. 1170 * @param src general purpose register. May not be null or zero-register. 1171 * @param aimm arithmetic immediate. Either unsigned 12-bit value or unsigned 24-bit value with 1172 * the lower 12-bit cleared. 1173 */ 1174 protected void add(int size, Register dst, Register src, int aimm) { 1175 assert !dst.equals(zr); 1176 assert !src.equals(zr); 1177 addSubImmInstruction(ADD, dst, src, aimm, generalFromSize(size)); 1178 } 1179 1180 /** 1181 * dst = src + aimm and sets condition flags. 1182 * 1183 * @param size register size. Has to be 32 or 64. 1184 * @param dst general purpose register. May not be null or stackpointer. 1185 * @param src general purpose register. May not be null or zero-register. 1186 * @param aimm arithmetic immediate. Either unsigned 12-bit value or unsigned 24-bit value with 1187 * the lower 12-bit cleared. 1188 */ 1189 protected void adds(int size, Register dst, Register src, int aimm) { 1190 assert !dst.equals(sp); 1191 assert !src.equals(zr); 1192 addSubImmInstruction(ADDS, dst, src, aimm, generalFromSize(size)); 1193 } 1194 1195 /** 1196 * dst = src - aimm. 1197 * 1198 * @param size register size. Has to be 32 or 64. 1199 * @param dst general purpose register. May not be null or zero-register. 1200 * @param src general purpose register. May not be null or zero-register. 1201 * @param aimm arithmetic immediate. Either unsigned 12-bit value or unsigned 24-bit value with 1202 * the lower 12-bit cleared. 1203 */ 1204 protected void sub(int size, Register dst, Register src, int aimm) { 1205 assert !dst.equals(zr); 1206 assert !src.equals(zr); 1207 addSubImmInstruction(SUB, dst, src, aimm, generalFromSize(size)); 1208 } 1209 1210 /** 1211 * dst = src - aimm and sets condition flags. 1212 * 1213 * @param size register size. Has to be 32 or 64. 1214 * @param dst general purpose register. May not be null or stackpointer. 1215 * @param src general purpose register. May not be null or zero-register. 1216 * @param aimm arithmetic immediate. Either unsigned 12-bit value or unsigned 24-bit value with 1217 * the lower 12-bit cleared. 1218 */ 1219 protected void subs(int size, Register dst, Register src, int aimm) { 1220 assert !dst.equals(sp); 1221 assert !src.equals(zr); 1222 addSubImmInstruction(SUBS, dst, src, aimm, generalFromSize(size)); 1223 } 1224 1225 private void addSubImmInstruction(Instruction instr, Register dst, Register src, int aimm, InstructionType type) { 1226 emitInt(type.encoding | instr.encoding | AddSubImmOp | encodeAimm(aimm) | rd(dst) | rs1(src)); 1227 } 1228 1229 /** 1230 * Encodes arithmetic immediate. 1231 * 1232 * @param imm Immediate has to be either an unsigned 12-bit value or an unsigned 24-bit value 1233 * with the lower 12 bits zero. 1234 * @return Representation of immediate for use with arithmetic instructions. 1235 */ 1236 private static int encodeAimm(int imm) { 1237 assert isAimm(imm) : "Immediate has to be legal arithmetic immediate value " + imm; 1238 if (NumUtil.isUnsignedNbit(12, imm)) { 1239 return imm << ImmediateOffset; 1240 } else { 1241 // First 12-bit are zero, so shift immediate 12-bit and set flag to indicate 1242 // shifted immediate value. 1243 return (imm >>> 12 << ImmediateOffset) | AddSubShift12; 1244 } 1245 } 1246 1247 /** 1248 * Checks whether immediate can be encoded as an arithmetic immediate. 1249 * 1250 * @param imm Immediate has to be either an unsigned 12bit value or un unsigned 24bit value with 1251 * the lower 12 bits 0. 1252 * @return true if valid arithmetic immediate, false otherwise. 1253 */ 1254 protected static boolean isAimm(int imm) { 1255 return NumUtil.isUnsignedNbit(12, imm) || NumUtil.isUnsignedNbit(12, imm >>> 12) && (imm & 0xfff) == 0; 1256 } 1257 1258 /* Logical (immediate) (5.4.2) */ 1259 1260 /** 1261 * dst = src & bimm. 1262 * 1263 * @param size register size. Has to be 32 or 64. 1264 * @param dst general purpose register. May not be null or zero-register. 1265 * @param src general purpose register. May not be null or stack-pointer. 1266 * @param bimm logical immediate. See {@link LogicalImmediateTable} for exact definition. 1267 */ 1268 public void and(int size, Register dst, Register src, long bimm) { 1269 assert !dst.equals(zr); 1270 assert !src.equals(sp); 1271 logicalImmInstruction(AND, dst, src, bimm, generalFromSize(size)); 1272 } 1273 1274 /** 1275 * dst = src & bimm and sets condition flags. 1276 * 1277 * @param size register size. Has to be 32 or 64. 1278 * @param dst general purpose register. May not be null or stack-pointer. 1279 * @param src general purpose register. May not be null or stack-pointer. 1280 * @param bimm logical immediate. See {@link LogicalImmediateTable} for exact definition. 1281 */ 1282 public void ands(int size, Register dst, Register src, long bimm) { 1283 assert !dst.equals(sp); 1284 assert !src.equals(sp); 1285 logicalImmInstruction(ANDS, dst, src, bimm, generalFromSize(size)); 1286 } 1287 1288 /** 1289 * dst = src ^ bimm. 1290 * 1291 * @param size register size. Has to be 32 or 64. 1292 * @param dst general purpose register. May not be null or zero-register. 1293 * @param src general purpose register. May not be null or stack-pointer. 1294 * @param bimm logical immediate. See {@link LogicalImmediateTable} for exact definition. 1295 */ 1296 public void eor(int size, Register dst, Register src, long bimm) { 1297 assert !dst.equals(zr); 1298 assert !src.equals(sp); 1299 logicalImmInstruction(EOR, dst, src, bimm, generalFromSize(size)); 1300 } 1301 1302 /** 1303 * dst = src | bimm. 1304 * 1305 * @param size register size. Has to be 32 or 64. 1306 * @param dst general purpose register. May not be null or zero-register. 1307 * @param src general purpose register. May not be null or stack-pointer. 1308 * @param bimm logical immediate. See {@link LogicalImmediateTable} for exact definition. 1309 */ 1310 protected void orr(int size, Register dst, Register src, long bimm) { 1311 assert !dst.equals(zr); 1312 assert !src.equals(sp); 1313 logicalImmInstruction(ORR, dst, src, bimm, generalFromSize(size)); 1314 } 1315 1316 private void logicalImmInstruction(Instruction instr, Register dst, Register src, long bimm, InstructionType type) { 1317 // Mask higher bits off, since we always pass longs around even for the 32-bit instruction. 1318 long bimmValue; 1319 if (type == General32) { 1320 assert (bimm >> 32) == 0 || (bimm >> 32) == -1L : "Higher order bits for 32-bit instruction must either all be 0 or 1."; 1321 bimmValue = bimm & NumUtil.getNbitNumberLong(32); 1322 } else { 1323 bimmValue = bimm; 1324 } 1325 int immEncoding = LogicalImmediateTable.getLogicalImmEncoding(type == General64, bimmValue); 1326 emitInt(type.encoding | instr.encoding | LogicalImmOp | immEncoding | rd(dst) | rs1(src)); 1327 } 1328 1329 /* Move (wide immediate) (5.4.3) */ 1330 1331 /** 1332 * dst = uimm16 << shiftAmt. 1333 * 1334 * @param size register size. Has to be 32 or 64. 1335 * @param dst general purpose register. May not be null, stackpointer or zero-register. 1336 * @param uimm16 16-bit unsigned immediate 1337 * @param shiftAmt amount by which uimm16 is left shifted. Can be any multiple of 16 smaller 1338 * than size. 1339 */ 1340 protected void movz(int size, Register dst, int uimm16, int shiftAmt) { 1341 moveWideImmInstruction(MOVZ, dst, uimm16, shiftAmt, generalFromSize(size)); 1342 } 1343 1344 /** 1345 * dst = ~(uimm16 << shiftAmt). 1346 * 1347 * @param size register size. Has to be 32 or 64. 1348 * @param dst general purpose register. May not be null, stackpointer or zero-register. 1349 * @param uimm16 16-bit unsigned immediate 1350 * @param shiftAmt amount by which uimm16 is left shifted. Can be any multiple of 16 smaller 1351 * than size. 1352 */ 1353 protected void movn(int size, Register dst, int uimm16, int shiftAmt) { 1354 moveWideImmInstruction(MOVN, dst, uimm16, shiftAmt, generalFromSize(size)); 1355 } 1356 1357 /** 1358 * dst<pos+15:pos> = uimm16. 1359 * 1360 * @param size register size. Has to be 32 or 64. 1361 * @param dst general purpose register. May not be null, stackpointer or zero-register. 1362 * @param uimm16 16-bit unsigned immediate 1363 * @param pos position into which uimm16 is inserted. Can be any multiple of 16 smaller than 1364 * size. 1365 */ 1366 protected void movk(int size, Register dst, int uimm16, int pos) { 1367 moveWideImmInstruction(MOVK, dst, uimm16, pos, generalFromSize(size)); 1368 } 1369 1370 private void moveWideImmInstruction(Instruction instr, Register dst, int uimm16, int shiftAmt, InstructionType type) { 1371 assert dst.getRegisterCategory().equals(CPU); 1372 assert NumUtil.isUnsignedNbit(16, uimm16) : "Immediate has to be unsigned 16bit"; 1373 assert shiftAmt == 0 || shiftAmt == 16 || (type == InstructionType.General64 && (shiftAmt == 32 || shiftAmt == 48)) : "Invalid shift amount: " + shiftAmt; 1374 int shiftValue = shiftAmt >> 4; 1375 emitInt(type.encoding | instr.encoding | MoveWideImmOp | rd(dst) | uimm16 << MoveWideImmOffset | shiftValue << MoveWideShiftOffset); 1376 } 1377 1378 /* Bitfield Operations (5.4.5) */ 1379 1380 /** 1381 * Bitfield move. 1382 * 1383 * @param size register size. Has to be 32 or 64. 1384 * @param dst general purpose register. May not be null, stackpointer or zero-register. 1385 * @param src general purpose register. May not be null, stackpointer or zero-register. 1386 * @param r must be in the range 0 to size - 1 1387 * @param s must be in the range 0 to size - 1 1388 */ 1389 protected void bfm(int size, Register dst, Register src, int r, int s) { 1390 bitfieldInstruction(BFM, dst, src, r, s, generalFromSize(size)); 1391 } 1392 1393 /** 1394 * Unsigned bitfield move. 1395 * 1396 * @param size register size. Has to be 32 or 64. 1397 * @param dst general purpose register. May not be null, stackpointer or zero-register. 1398 * @param src general purpose register. May not be null, stackpointer or zero-register. 1399 * @param r must be in the range 0 to size - 1 1400 * @param s must be in the range 0 to size - 1 1401 */ 1402 protected void ubfm(int size, Register dst, Register src, int r, int s) { 1403 bitfieldInstruction(UBFM, dst, src, r, s, generalFromSize(size)); 1404 } 1405 1406 /** 1407 * Signed bitfield move. 1408 * 1409 * @param size register size. Has to be 32 or 64. 1410 * @param dst general purpose register. May not be null, stackpointer or zero-register. 1411 * @param src general purpose register. May not be null, stackpointer or zero-register. 1412 * @param r must be in the range 0 to size - 1 1413 * @param s must be in the range 0 to size - 1 1414 */ 1415 protected void sbfm(int size, Register dst, Register src, int r, int s) { 1416 bitfieldInstruction(SBFM, dst, src, r, s, generalFromSize(size)); 1417 } 1418 1419 private void bitfieldInstruction(Instruction instr, Register dst, Register src, int r, int s, InstructionType type) { 1420 assert !dst.equals(sp) && !dst.equals(zr); 1421 assert !src.equals(sp) && !src.equals(zr); 1422 assert s >= 0 && s < type.width && r >= 0 && r < type.width; 1423 int sf = type == General64 ? 1 << ImmediateSizeOffset : 0; 1424 emitInt(type.encoding | instr.encoding | BitfieldImmOp | sf | r << ImmediateRotateOffset | s << ImmediateOffset | rd(dst) | rs1(src)); 1425 } 1426 1427 /* Extract (Immediate) (5.4.6) */ 1428 1429 /** 1430 * Extract. dst = src1:src2<lsb+31:lsb> 1431 * 1432 * @param size register size. Has to be 32 or 64. 1433 * @param dst general purpose register. May not be null or stackpointer. 1434 * @param src1 general purpose register. May not be null or stackpointer. 1435 * @param src2 general purpose register. May not be null or stackpointer. 1436 * @param lsb must be in range 0 to size - 1. 1437 */ 1438 protected void extr(int size, Register dst, Register src1, Register src2, int lsb) { 1439 assert !dst.equals(sp); 1440 assert !src1.equals(sp); 1441 assert !src2.equals(sp); 1442 InstructionType type = generalFromSize(size); 1443 assert lsb >= 0 && lsb < type.width; 1444 int sf = type == General64 ? 1 << ImmediateSizeOffset : 0; 1445 emitInt(type.encoding | EXTR.encoding | sf | lsb << ImmediateOffset | rd(dst) | rs1(src1) | rs2(src2)); 1446 } 1447 1448 /* Arithmetic (shifted register) (5.5.1) */ 1449 1450 /** 1451 * dst = src1 + shiftType(src2, imm). 1452 * 1453 * @param size register size. Has to be 32 or 64. 1454 * @param dst general purpose register. May not be null or stackpointer. 1455 * @param src1 general purpose register. May not be null or stackpointer. 1456 * @param src2 general purpose register. May not be null or stackpointer. 1457 * @param shiftType any type but ROR. 1458 * @param imm must be in range 0 to size - 1. 1459 */ 1460 protected void add(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) { 1461 addSubShiftedInstruction(ADD, dst, src1, src2, shiftType, imm, generalFromSize(size)); 1462 } 1463 1464 /** 1465 * dst = src1 + shiftType(src2, imm) and sets condition flags. 1466 * 1467 * @param size register size. Has to be 32 or 64. 1468 * @param dst general purpose register. May not be null or stackpointer. 1469 * @param src1 general purpose register. May not be null or stackpointer. 1470 * @param src2 general purpose register. May not be null or stackpointer. 1471 * @param shiftType any type but ROR. 1472 * @param imm must be in range 0 to size - 1. 1473 */ 1474 protected void adds(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) { 1475 addSubShiftedInstruction(ADDS, dst, src1, src2, shiftType, imm, generalFromSize(size)); 1476 } 1477 1478 /** 1479 * dst = src1 - shiftType(src2, imm). 1480 * 1481 * @param size register size. Has to be 32 or 64. 1482 * @param dst general purpose register. May not be null or stackpointer. 1483 * @param src1 general purpose register. May not be null or stackpointer. 1484 * @param src2 general purpose register. May not be null or stackpointer. 1485 * @param shiftType any type but ROR. 1486 * @param imm must be in range 0 to size - 1. 1487 */ 1488 protected void sub(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) { 1489 addSubShiftedInstruction(SUB, dst, src1, src2, shiftType, imm, generalFromSize(size)); 1490 } 1491 1492 /** 1493 * dst = src1 - shiftType(src2, imm) and sets condition flags. 1494 * 1495 * @param size register size. Has to be 32 or 64. 1496 * @param dst general purpose register. May not be null or stackpointer. 1497 * @param src1 general purpose register. May not be null or stackpointer. 1498 * @param src2 general purpose register. May not be null or stackpointer. 1499 * @param shiftType any type but ROR. 1500 * @param imm must be in range 0 to size - 1. 1501 */ 1502 protected void subs(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) { 1503 addSubShiftedInstruction(SUBS, dst, src1, src2, shiftType, imm, generalFromSize(size)); 1504 } 1505 1506 private void addSubShiftedInstruction(Instruction instr, Register dst, Register src1, Register src2, ShiftType shiftType, int imm, InstructionType type) { 1507 assert shiftType != ShiftType.ROR; 1508 assert imm >= 0 && imm < type.width; 1509 emitInt(type.encoding | instr.encoding | AddSubShiftedOp | imm << ImmediateOffset | shiftType.encoding << ShiftTypeOffset | rd(dst) | rs1(src1) | rs2(src2)); 1510 } 1511 1512 /* Arithmetic (extended register) (5.5.2) */ 1513 /** 1514 * dst = src1 + extendType(src2) << imm. 1515 * 1516 * @param size register size. Has to be 32 or 64. 1517 * @param dst general purpose register. May not be null or zero-register.. 1518 * @param src1 general purpose register. May not be null or zero-register. 1519 * @param src2 general purpose register. May not be null or stackpointer. 1520 * @param extendType defines how src2 is extended to the same size as src1. 1521 * @param shiftAmt must be in range 0 to 4. 1522 */ 1523 public void add(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) { 1524 assert !dst.equals(zr); 1525 assert !src1.equals(zr); 1526 assert !src2.equals(sp); 1527 addSubExtendedInstruction(ADD, dst, src1, src2, extendType, shiftAmt, generalFromSize(size)); 1528 } 1529 1530 /** 1531 * dst = src1 + extendType(src2) << imm and sets condition flags. 1532 * 1533 * @param size register size. Has to be 32 or 64. 1534 * @param dst general purpose register. May not be null or stackpointer.. 1535 * @param src1 general purpose register. May not be null or zero-register. 1536 * @param src2 general purpose register. May not be null or stackpointer. 1537 * @param extendType defines how src2 is extended to the same size as src1. 1538 * @param shiftAmt must be in range 0 to 4. 1539 */ 1540 protected void adds(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) { 1541 assert !dst.equals(sp); 1542 assert !src1.equals(zr); 1543 assert !src2.equals(sp); 1544 addSubExtendedInstruction(ADDS, dst, src1, src2, extendType, shiftAmt, generalFromSize(size)); 1545 } 1546 1547 /** 1548 * dst = src1 - extendType(src2) << imm. 1549 * 1550 * @param size register size. Has to be 32 or 64. 1551 * @param dst general purpose register. May not be null or zero-register.. 1552 * @param src1 general purpose register. May not be null or zero-register. 1553 * @param src2 general purpose register. May not be null or stackpointer. 1554 * @param extendType defines how src2 is extended to the same size as src1. 1555 * @param shiftAmt must be in range 0 to 4. 1556 */ 1557 protected void sub(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) { 1558 assert !dst.equals(zr); 1559 assert !src1.equals(zr); 1560 assert !src2.equals(sp); 1561 addSubExtendedInstruction(SUB, dst, src1, src2, extendType, shiftAmt, generalFromSize(size)); 1562 } 1563 1564 /** 1565 * dst = src1 - extendType(src2) << imm and sets flags. 1566 * 1567 * @param size register size. Has to be 32 or 64. 1568 * @param dst general purpose register. May not be null or stackpointer.. 1569 * @param src1 general purpose register. May not be null or zero-register. 1570 * @param src2 general purpose register. May not be null or stackpointer. 1571 * @param extendType defines how src2 is extended to the same size as src1. 1572 * @param shiftAmt must be in range 0 to 4. 1573 */ 1574 protected void subs(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) { 1575 assert !dst.equals(sp); 1576 assert !src1.equals(zr); 1577 assert !src2.equals(sp); 1578 addSubExtendedInstruction(SUBS, dst, src1, src2, extendType, shiftAmt, generalFromSize(size)); 1579 } 1580 1581 private void addSubExtendedInstruction(Instruction instr, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt, InstructionType type) { 1582 assert shiftAmt >= 0 && shiftAmt <= 4; 1583 emitInt(type.encoding | instr.encoding | AddSubExtendedOp | shiftAmt << ImmediateOffset | extendType.encoding << ExtendTypeOffset | rd(dst) | rs1(src1) | rs2(src2)); 1584 } 1585 1586 /* Logical (shifted register) (5.5.3) */ 1587 /** 1588 * dst = src1 & shiftType(src2, imm). 1589 * 1590 * @param size register size. Has to be 32 or 64. 1591 * @param dst general purpose register. May not be null or stackpointer. 1592 * @param src1 general purpose register. May not be null or stackpointer. 1593 * @param src2 general purpose register. May not be null or stackpointer. 1594 * @param shiftType all types allowed, may not be null. 1595 * @param shiftAmt must be in range 0 to size - 1. 1596 */ 1597 protected void and(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) { 1598 logicalRegInstruction(AND, dst, src1, src2, shiftType, shiftAmt, generalFromSize(size)); 1599 } 1600 1601 /** 1602 * dst = src1 & shiftType(src2, imm) and sets condition flags. 1603 * 1604 * @param size register size. Has to be 32 or 64. 1605 * @param dst general purpose register. May not be null or stackpointer. 1606 * @param src1 general purpose register. May not be null or stackpointer. 1607 * @param src2 general purpose register. May not be null or stackpointer. 1608 * @param shiftType all types allowed, may not be null. 1609 * @param shiftAmt must be in range 0 to size - 1. 1610 */ 1611 protected void ands(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) { 1612 logicalRegInstruction(ANDS, dst, src1, src2, shiftType, shiftAmt, generalFromSize(size)); 1613 } 1614 1615 /** 1616 * dst = src1 & ~(shiftType(src2, imm)). 1617 * 1618 * @param size register size. Has to be 32 or 64. 1619 * @param dst general purpose register. May not be null or stackpointer. 1620 * @param src1 general purpose register. May not be null or stackpointer. 1621 * @param src2 general purpose register. May not be null or stackpointer. 1622 * @param shiftType all types allowed, may not be null. 1623 * @param shiftAmt must be in range 0 to size - 1. 1624 */ 1625 protected void bic(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) { 1626 logicalRegInstruction(BIC, dst, src1, src2, shiftType, shiftAmt, generalFromSize(size)); 1627 } 1628 1629 /** 1630 * dst = src1 & ~(shiftType(src2, imm)) and sets condition flags. 1631 * 1632 * @param size register size. Has to be 32 or 64. 1633 * @param dst general purpose register. May not be null or stackpointer. 1634 * @param src1 general purpose register. May not be null or stackpointer. 1635 * @param src2 general purpose register. May not be null or stackpointer. 1636 * @param shiftType all types allowed, may not be null. 1637 * @param shiftAmt must be in range 0 to size - 1. 1638 */ 1639 protected void bics(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) { 1640 logicalRegInstruction(BICS, dst, src1, src2, shiftType, shiftAmt, generalFromSize(size)); 1641 } 1642 1643 /** 1644 * dst = src1 ^ ~(shiftType(src2, imm)). 1645 * 1646 * @param size register size. Has to be 32 or 64. 1647 * @param dst general purpose register. May not be null or stackpointer. 1648 * @param src1 general purpose register. May not be null or stackpointer. 1649 * @param src2 general purpose register. May not be null or stackpointer. 1650 * @param shiftType all types allowed, may not be null. 1651 * @param shiftAmt must be in range 0 to size - 1. 1652 */ 1653 protected void eon(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) { 1654 logicalRegInstruction(EON, dst, src1, src2, shiftType, shiftAmt, generalFromSize(size)); 1655 } 1656 1657 /** 1658 * dst = src1 ^ shiftType(src2, imm). 1659 * 1660 * @param size register size. Has to be 32 or 64. 1661 * @param dst general purpose register. May not be null or stackpointer. 1662 * @param src1 general purpose register. May not be null or stackpointer. 1663 * @param src2 general purpose register. May not be null or stackpointer. 1664 * @param shiftType all types allowed, may not be null. 1665 * @param shiftAmt must be in range 0 to size - 1. 1666 */ 1667 protected void eor(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) { 1668 logicalRegInstruction(EOR, dst, src1, src2, shiftType, shiftAmt, generalFromSize(size)); 1669 } 1670 1671 /** 1672 * dst = src1 | shiftType(src2, imm). 1673 * 1674 * @param size register size. Has to be 32 or 64. 1675 * @param dst general purpose register. May not be null or stackpointer. 1676 * @param src1 general purpose register. May not be null or stackpointer. 1677 * @param src2 general purpose register. May not be null or stackpointer. 1678 * @param shiftType all types allowed, may not be null. 1679 * @param shiftAmt must be in range 0 to size - 1. 1680 */ 1681 protected void orr(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) { 1682 logicalRegInstruction(ORR, dst, src1, src2, shiftType, shiftAmt, generalFromSize(size)); 1683 } 1684 1685 /** 1686 * dst = src1 | ~(shiftType(src2, imm)). 1687 * 1688 * @param size register size. Has to be 32 or 64. 1689 * @param dst general purpose register. May not be null or stackpointer. 1690 * @param src1 general purpose register. May not be null or stackpointer. 1691 * @param src2 general purpose register. May not be null or stackpointer. 1692 * @param shiftType all types allowed, may not be null. 1693 * @param shiftAmt must be in range 0 to size - 1. 1694 */ 1695 protected void orn(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) { 1696 logicalRegInstruction(ORN, dst, src1, src2, shiftType, shiftAmt, generalFromSize(size)); 1697 } 1698 1699 private void logicalRegInstruction(Instruction instr, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt, InstructionType type) { 1700 assert !dst.equals(sp); 1701 assert !src1.equals(sp); 1702 assert !src2.equals(sp); 1703 assert shiftAmt >= 0 && shiftAmt < type.width; 1704 emitInt(type.encoding | instr.encoding | LogicalShiftOp | shiftAmt << ImmediateOffset | shiftType.encoding << ShiftTypeOffset | rd(dst) | rs1(src1) | rs2(src2)); 1705 } 1706 1707 /* Variable Shift (5.5.4) */ 1708 /** 1709 * dst = src1 >> (src2 & log2(size)). 1710 * 1711 * @param size register size. Has to be 32 or 64. 1712 * @param dst general purpose register. May not be null or stackpointer. 1713 * @param src1 general purpose register. May not be null or stackpointer. 1714 * @param src2 general purpose register. May not be null or stackpointer. 1715 */ 1716 protected void asr(int size, Register dst, Register src1, Register src2) { 1717 dataProcessing2SourceOp(ASRV, dst, src1, src2, generalFromSize(size)); 1718 } 1719 1720 /** 1721 * dst = src1 << (src2 & log2(size)). 1722 * 1723 * @param size register size. Has to be 32 or 64. 1724 * @param dst general purpose register. May not be null or stackpointer. 1725 * @param src1 general purpose register. May not be null or stackpointer. 1726 * @param src2 general purpose register. May not be null or stackpointer. 1727 */ 1728 protected void lsl(int size, Register dst, Register src1, Register src2) { 1729 dataProcessing2SourceOp(LSLV, dst, src1, src2, generalFromSize(size)); 1730 } 1731 1732 /** 1733 * dst = src1 >>> (src2 & log2(size)). 1734 * 1735 * @param size register size. Has to be 32 or 64. 1736 * @param dst general purpose register. May not be null or stackpointer. 1737 * @param src1 general purpose register. May not be null or stackpointer. 1738 * @param src2 general purpose register. May not be null or stackpointer. 1739 */ 1740 protected void lsr(int size, Register dst, Register src1, Register src2) { 1741 dataProcessing2SourceOp(LSRV, dst, src1, src2, generalFromSize(size)); 1742 } 1743 1744 /** 1745 * dst = rotateRight(src1, (src2 & log2(size))). 1746 * 1747 * @param size register size. Has to be 32 or 64. 1748 * @param dst general purpose register. May not be null or stackpointer. 1749 * @param src1 general purpose register. May not be null or stackpointer. 1750 * @param src2 general purpose register. May not be null or stackpointer. 1751 */ 1752 protected void ror(int size, Register dst, Register src1, Register src2) { 1753 dataProcessing2SourceOp(RORV, dst, src1, src2, generalFromSize(size)); 1754 } 1755 1756 /* Bit Operations (5.5.5) */ 1757 1758 /** 1759 * Counts leading sign bits. Sets Wd to the number of consecutive bits following the topmost bit 1760 * in dst, that are the same as the topmost bit. The count does not include the topmost bit 1761 * itself , so the result will be in the range 0 to size-1 inclusive. 1762 * 1763 * @param size register size. Has to be 32 or 64. 1764 * @param dst general purpose register. May not be null, zero-register or the stackpointer. 1765 * @param src source register. May not be null, zero-register or the stackpointer. 1766 */ 1767 protected void cls(int size, Register dst, Register src) { 1768 dataProcessing1SourceOp(CLS, dst, src, generalFromSize(size)); 1769 } 1770 1771 /** 1772 * Counts leading zeros. 1773 * 1774 * @param size register size. Has to be 32 or 64. 1775 * @param dst general purpose register. May not be null, zero-register or the stackpointer. 1776 * @param src source register. May not be null, zero-register or the stackpointer. 1777 */ 1778 public void clz(int size, Register dst, Register src) { 1779 dataProcessing1SourceOp(CLZ, dst, src, generalFromSize(size)); 1780 } 1781 1782 /** 1783 * Reverses bits. 1784 * 1785 * @param size register size. Has to be 32 or 64. 1786 * @param dst general purpose register. May not be null, zero-register or the stackpointer. 1787 * @param src source register. May not be null, zero-register or the stackpointer. 1788 */ 1789 protected void rbit(int size, Register dst, Register src) { 1790 dataProcessing1SourceOp(RBIT, dst, src, generalFromSize(size)); 1791 } 1792 1793 /** 1794 * Reverses bytes. 1795 * 1796 * @param size register size. Has to be 32 or 64. 1797 * @param dst general purpose register. May not be null or the stackpointer. 1798 * @param src source register. May not be null or the stackpointer. 1799 */ 1800 public void rev(int size, Register dst, Register src) { 1801 if (size == 64) { 1802 dataProcessing1SourceOp(REVX, dst, src, generalFromSize(size)); 1803 } else { 1804 assert size == 32; 1805 dataProcessing1SourceOp(REVW, dst, src, generalFromSize(size)); 1806 } 1807 } 1808 1809 /* Conditional Data Processing (5.5.6) */ 1810 1811 /** 1812 * Conditional select. dst = src1 if condition else src2. 1813 * 1814 * @param size register size. Has to be 32 or 64. 1815 * @param dst general purpose register. May not be null or the stackpointer. 1816 * @param src1 general purpose register. May not be null or the stackpointer. 1817 * @param src2 general purpose register. May not be null or the stackpointer. 1818 * @param condition any condition flag. May not be null. 1819 */ 1820 protected void csel(int size, Register dst, Register src1, Register src2, ConditionFlag condition) { 1821 conditionalSelectInstruction(CSEL, dst, src1, src2, condition, generalFromSize(size)); 1822 } 1823 1824 /** 1825 * Conditional select negate. dst = src1 if condition else -src2. 1826 * 1827 * @param size register size. Has to be 32 or 64. 1828 * @param dst general purpose register. May not be null or the stackpointer. 1829 * @param src1 general purpose register. May not be null or the stackpointer. 1830 * @param src2 general purpose register. May not be null or the stackpointer. 1831 * @param condition any condition flag. May not be null. 1832 */ 1833 protected void csneg(int size, Register dst, Register src1, Register src2, ConditionFlag condition) { 1834 conditionalSelectInstruction(CSNEG, dst, src1, src2, condition, generalFromSize(size)); 1835 } 1836 1837 /** 1838 * Conditional increase. dst = src1 if condition else src2 + 1. 1839 * 1840 * @param size register size. Has to be 32 or 64. 1841 * @param dst general purpose register. May not be null or the stackpointer. 1842 * @param src1 general purpose register. May not be null or the stackpointer. 1843 * @param src2 general purpose register. May not be null or the stackpointer. 1844 * @param condition any condition flag. May not be null. 1845 */ 1846 protected void csinc(int size, Register dst, Register src1, Register src2, ConditionFlag condition) { 1847 conditionalSelectInstruction(CSINC, dst, src1, src2, condition, generalFromSize(size)); 1848 } 1849 1850 private void conditionalSelectInstruction(Instruction instr, Register dst, Register src1, Register src2, ConditionFlag condition, InstructionType type) { 1851 assert !dst.equals(sp); 1852 assert !src1.equals(sp); 1853 assert !src2.equals(sp); 1854 emitInt(type.encoding | instr.encoding | ConditionalSelectOp | rd(dst) | rs1(src1) | rs2(src2) | condition.encoding << ConditionalConditionOffset); 1855 } 1856 1857 /* Integer Multiply/Divide (5.6) */ 1858 1859 /** 1860 * dst = src1 * src2 + src3. 1861 * 1862 * @param size register size. Has to be 32 or 64. 1863 * @param dst general purpose register. May not be null or the stackpointer. 1864 * @param src1 general purpose register. May not be null or the stackpointer. 1865 * @param src2 general purpose register. May not be null or the stackpointer. 1866 * @param src3 general purpose register. May not be null or the stackpointer. 1867 */ 1868 protected void madd(int size, Register dst, Register src1, Register src2, Register src3) { 1869 mulInstruction(MADD, dst, src1, src2, src3, generalFromSize(size)); 1870 } 1871 1872 /** 1873 * dst = src3 - src1 * src2. 1874 * 1875 * @param size register size. Has to be 32 or 64. 1876 * @param dst general purpose register. May not be null or the stackpointer. 1877 * @param src1 general purpose register. May not be null or the stackpointer. 1878 * @param src2 general purpose register. May not be null or the stackpointer. 1879 * @param src3 general purpose register. May not be null or the stackpointer. 1880 */ 1881 protected void msub(int size, Register dst, Register src1, Register src2, Register src3) { 1882 mulInstruction(MSUB, dst, src1, src2, src3, generalFromSize(size)); 1883 } 1884 1885 /** 1886 * Signed multiply high. dst = (src1 * src2)[127:64] 1887 * 1888 * @param dst general purpose register. May not be null or the stackpointer. 1889 * @param src1 general purpose register. May not be null or the stackpointer. 1890 * @param src2 general purpose register. May not be null or the stackpointer. 1891 */ 1892 protected void smulh(Register dst, Register src1, Register src2) { 1893 assert !dst.equals(sp); 1894 assert !src1.equals(sp); 1895 assert !src2.equals(sp); 1896 emitInt(0b10011011010 << 21 | dst.encoding | rs1(src1) | rs2(src2) | 0b011111 << ImmediateOffset); 1897 } 1898 1899 /** 1900 * unsigned multiply high. dst = (src1 * src2)[127:64] 1901 * 1902 * @param dst general purpose register. May not be null or the stackpointer. 1903 * @param src1 general purpose register. May not be null or the stackpointer. 1904 * @param src2 general purpose register. May not be null or the stackpointer. 1905 */ 1906 protected void umulh(Register dst, Register src1, Register src2) { 1907 assert !dst.equals(sp); 1908 assert !src1.equals(sp); 1909 assert !src2.equals(sp); 1910 emitInt(0b10011011110 << 21 | dst.encoding | rs1(src1) | rs2(src2) | 0b011111 << ImmediateOffset); 1911 } 1912 1913 /** 1914 * unsigned multiply add-long. xDst = xSrc3 + (wSrc1 * wSrc2) 1915 * 1916 * @param dst general purpose register. May not be null or the stackpointer. 1917 * @param src1 general purpose register. May not be null or the stackpointer. 1918 * @param src2 general purpose register. May not be null or the stackpointer. 1919 * @param src3 general purpose register. May not be null or the stackpointer. 1920 */ 1921 protected void umaddl(Register dst, Register src1, Register src2, Register src3) { 1922 assert !dst.equals(sp); 1923 assert !src1.equals(sp); 1924 assert !src2.equals(sp); 1925 assert !src3.equals(sp); 1926 emitInt(0b10011011101 << 21 | dst.encoding | rs1(src1) | rs2(src2) | 0b011111 << ImmediateOffset); 1927 } 1928 1929 /** 1930 * signed multiply add-long. xDst = xSrc3 + (wSrc1 * wSrc2) 1931 * 1932 * @param dst general purpose register. May not be null or the stackpointer. 1933 * @param src1 general purpose register. May not be null or the stackpointer. 1934 * @param src2 general purpose register. May not be null or the stackpointer. 1935 * @param src3 general purpose register. May not be null or the stackpointer. 1936 */ 1937 protected void smaddl(Register dst, Register src1, Register src2, Register src3) { 1938 assert !dst.equals(sp); 1939 assert !src1.equals(sp); 1940 assert !src2.equals(sp); 1941 assert !src3.equals(sp); 1942 emitInt(0b10011011001 << 21 | dst.encoding | rs1(src1) | rs2(src2) | rs3(src3)); 1943 } 1944 1945 private void mulInstruction(Instruction instr, Register dst, Register src1, Register src2, Register src3, InstructionType type) { 1946 assert !dst.equals(sp); 1947 assert !src1.equals(sp); 1948 assert !src2.equals(sp); 1949 assert !src3.equals(sp); 1950 emitInt(type.encoding | instr.encoding | MulOp | rd(dst) | rs1(src1) | rs2(src2) | rs3(src3)); 1951 } 1952 1953 /** 1954 * Signed divide. dst = src1 / src2. 1955 * 1956 * @param size register size. Has to be 32 or 64. 1957 * @param dst general purpose register. May not be null or the stackpointer. 1958 * @param src1 general purpose register. May not be null or the stackpointer. 1959 * @param src2 general purpose register. May not be null or the stackpointer. 1960 */ 1961 public void sdiv(int size, Register dst, Register src1, Register src2) { 1962 dataProcessing2SourceOp(SDIV, dst, src1, src2, generalFromSize(size)); 1963 } 1964 1965 /** 1966 * Unsigned divide. dst = src1 / src2. 1967 * 1968 * @param size register size. Has to be 32 or 64. 1969 * @param dst general purpose register. May not be null or the stackpointer. 1970 * @param src1 general purpose register. May not be null or the stackpointer. 1971 * @param src2 general purpose register. May not be null or the stackpointer. 1972 */ 1973 public void udiv(int size, Register dst, Register src1, Register src2) { 1974 dataProcessing2SourceOp(UDIV, dst, src1, src2, generalFromSize(size)); 1975 } 1976 1977 private void dataProcessing1SourceOp(Instruction instr, Register dst, Register src, InstructionType type) { 1978 emitInt(type.encoding | instr.encoding | DataProcessing1SourceOp | rd(dst) | rs1(src)); 1979 } 1980 1981 private void dataProcessing2SourceOp(Instruction instr, Register dst, Register src1, Register src2, InstructionType type) { 1982 assert !dst.equals(sp); 1983 assert !src1.equals(sp); 1984 assert !src2.equals(sp); 1985 emitInt(type.encoding | instr.encoding | DataProcessing2SourceOp | rd(dst) | rs1(src1) | rs2(src2)); 1986 } 1987 1988 /* Floating point operations */ 1989 1990 /* Load-Store Single FP register (5.7.1.1) */ 1991 /** 1992 * Floating point load. 1993 * 1994 * @param size number of bits read from memory into rt. Must be 32 or 64. 1995 * @param rt floating point register. May not be null. 1996 * @param address all addressing modes allowed. May not be null. 1997 */ 1998 public void fldr(int size, Register rt, AArch64Address address) { 1999 assert rt.getRegisterCategory().equals(SIMD); 2000 assert size == 32 || size == 64; 2001 int transferSize = NumUtil.log2Ceil(size / 8); 2002 loadStoreInstruction(LDR, rt, address, InstructionType.FP32, transferSize); 2003 } 2004 2005 /** 2006 * Floating point store. 2007 * 2008 * @param size number of bits read from memory into rt. Must be 32 or 64. 2009 * @param rt floating point register. May not be null. 2010 * @param address all addressing modes allowed. May not be null. 2011 */ 2012 public void fstr(int size, Register rt, AArch64Address address) { 2013 assert rt.getRegisterCategory().equals(SIMD); 2014 assert size == 32 || size == 64; 2015 int transferSize = NumUtil.log2Ceil(size / 8); 2016 loadStoreInstruction(STR, rt, address, InstructionType.FP64, transferSize); 2017 } 2018 2019 /* Floating-point Move (register) (5.7.2) */ 2020 2021 /** 2022 * Floating point move. 2023 * 2024 * @param size register size. Has to be 32 or 64. 2025 * @param dst floating point register. May not be null. 2026 * @param src floating point register. May not be null. 2027 */ 2028 protected void fmov(int size, Register dst, Register src) { 2029 fpDataProcessing1Source(FMOV, dst, src, floatFromSize(size)); 2030 } 2031 2032 /** 2033 * Move size bits from floating point register unchanged to general purpose register. 2034 * 2035 * @param size number of bits read from memory into rt. Must be 32 or 64. 2036 * @param dst general purpose register. May not be null, stack-pointer or zero-register 2037 * @param src floating point register. May not be null. 2038 */ 2039 protected void fmovFpu2Cpu(int size, Register dst, Register src) { 2040 assert dst.getRegisterCategory().equals(CPU); 2041 assert src.getRegisterCategory().equals(SIMD); 2042 fmovCpuFpuInstruction(dst, src, size == 64, Instruction.FMOVFPU2CPU); 2043 } 2044 2045 /** 2046 * Move size bits from general purpose register unchanged to floating point register. 2047 * 2048 * @param size register size. Has to be 32 or 64. 2049 * @param dst floating point register. May not be null. 2050 * @param src general purpose register. May not be null or stack-pointer. 2051 */ 2052 protected void fmovCpu2Fpu(int size, Register dst, Register src) { 2053 assert dst.getRegisterCategory().equals(SIMD); 2054 assert src.getRegisterCategory().equals(CPU); 2055 fmovCpuFpuInstruction(dst, src, size == 64, Instruction.FMOVCPU2FPU); 2056 } 2057 2058 private void fmovCpuFpuInstruction(Register dst, Register src, boolean is64bit, Instruction instr) { 2059 int sf = is64bit ? FP64.encoding | General64.encoding : FP32.encoding | General32.encoding; 2060 emitInt(sf | instr.encoding | FpConvertOp | rd(dst) | rs1(src)); 2061 } 2062 2063 /* Floating-point Move (immediate) (5.7.3) */ 2064 2065 /** 2066 * Move immediate into register. 2067 * 2068 * @param size register size. Has to be 32 or 64. 2069 * @param dst floating point register. May not be null. 2070 * @param imm immediate that is loaded into dst. If size is 32 only float immediates can be 2071 * loaded, i.e. (float) imm == imm must be true. In all cases 2072 * {@code isFloatImmediate}, respectively {@code #isDoubleImmediate} must be true 2073 * depending on size. 2074 */ 2075 protected void fmov(int size, Register dst, double imm) { 2076 assert dst.getRegisterCategory().equals(SIMD); 2077 InstructionType type = floatFromSize(size); 2078 int immEncoding; 2079 if (type == FP64) { 2080 immEncoding = getDoubleImmediate(imm); 2081 } else { 2082 assert imm == (float) imm : "float mov must use an immediate that can be represented using a float."; 2083 immEncoding = getFloatImmediate((float) imm); 2084 } 2085 emitInt(type.encoding | FMOV.encoding | FpImmOp | immEncoding | rd(dst)); 2086 } 2087 2088 private static int getDoubleImmediate(double imm) { 2089 assert isDoubleImmediate(imm); 2090 // bits: aBbb.bbbb.bbcd.efgh.0000.0000.0000.0000 2091 // 0000.0000.0000.0000.0000.0000.0000.0000 2092 long repr = Double.doubleToRawLongBits(imm); 2093 int a = (int) (repr >>> 63) << 7; 2094 int b = (int) ((repr >>> 61) & 0x1) << 6; 2095 int cToH = (int) (repr >>> 48) & 0x3f; 2096 return (a | b | cToH) << FpImmOffset; 2097 } 2098 2099 protected static boolean isDoubleImmediate(double imm) { 2100 // Valid values will have the form: 2101 // aBbb.bbbb.bbcd.efgh.0000.0000.0000.0000 2102 // 0000.0000.0000.0000.0000.0000.0000.0000 2103 long bits = Double.doubleToRawLongBits(imm); 2104 // lower 48 bits are cleared 2105 if ((bits & NumUtil.getNbitNumberLong(48)) != 0) { 2106 return false; 2107 } 2108 // bits[61..54] are all set or all cleared. 2109 long pattern = (bits >> 54) & NumUtil.getNbitNumberLong(7); 2110 if (pattern != 0 && pattern != NumUtil.getNbitNumberLong(7)) { 2111 return false; 2112 } 2113 // bits[62] and bits[61] are opposites. 2114 return ((bits ^ (bits << 1)) & (1L << 62)) != 0; 2115 } 2116 2117 private static int getFloatImmediate(float imm) { 2118 assert isFloatImmediate(imm); 2119 // bits: aBbb.bbbc.defg.h000.0000.0000.0000.0000 2120 int repr = Float.floatToRawIntBits(imm); 2121 int a = (repr >>> 31) << 7; 2122 int b = ((repr >>> 29) & 0x1) << 6; 2123 int cToH = (repr >>> 19) & NumUtil.getNbitNumberInt(6); 2124 return (a | b | cToH) << FpImmOffset; 2125 } 2126 2127 protected static boolean isFloatImmediate(float imm) { 2128 // Valid values will have the form: 2129 // aBbb.bbbc.defg.h000.0000.0000.0000.0000 2130 int bits = Float.floatToRawIntBits(imm); 2131 // lower 20 bits are cleared. 2132 if ((bits & NumUtil.getNbitNumberInt(19)) != 0) { 2133 return false; 2134 } 2135 // bits[29..25] are all set or all cleared 2136 int pattern = (bits >> 25) & NumUtil.getNbitNumberInt(5); 2137 if (pattern != 0 && pattern != NumUtil.getNbitNumberInt(5)) { 2138 return false; 2139 } 2140 // bits[29] and bits[30] have to be opposite 2141 return ((bits ^ (bits << 1)) & (1 << 30)) != 0; 2142 } 2143 2144 /* Convert Floating-point Precision (5.7.4.1) */ 2145 /* Converts float to double and vice-versa */ 2146 2147 /** 2148 * Convert float to double and vice-versa. 2149 * 2150 * @param srcSize size of source register in bits. 2151 * @param dst floating point register. May not be null. 2152 * @param src floating point register. May not be null. 2153 */ 2154 public void fcvt(int srcSize, Register dst, Register src) { 2155 if (srcSize == 32) { 2156 fpDataProcessing1Source(FCVTDS, dst, src, floatFromSize(srcSize)); 2157 } else { 2158 fpDataProcessing1Source(FCVTSD, dst, src, floatFromSize(srcSize)); 2159 } 2160 } 2161 2162 /* Convert to Integer (5.7.4.2) */ 2163 2164 /** 2165 * Convert floating point to integer. Rounds towards zero. 2166 * 2167 * @param targetSize size of integer register. 32 or 64. 2168 * @param srcSize size of floating point register. 32 or 64. 2169 * @param dst general purpose register. May not be null, the zero-register or the stackpointer. 2170 * @param src floating point register. May not be null. 2171 */ 2172 public void fcvtzs(int targetSize, int srcSize, Register dst, Register src) { 2173 assert !dst.equals(zr) && !dst.equals(sp); 2174 assert src.getRegisterCategory().equals(SIMD); 2175 fcvtCpuFpuInstruction(FCVTZS, dst, src, generalFromSize(targetSize), floatFromSize(srcSize)); 2176 } 2177 2178 /* Convert from Integer (5.7.4.2) */ 2179 /** 2180 * Converts integer to floating point. Uses rounding mode defined by FCPR. 2181 * 2182 * @param targetSize size of floating point register. 32 or 64. 2183 * @param srcSize size of integer register. 32 or 64. 2184 * @param dst floating point register. May not be null. 2185 * @param src general purpose register. May not be null or the stackpointer. 2186 */ 2187 public void scvtf(int targetSize, int srcSize, Register dst, Register src) { 2188 assert dst.getRegisterCategory().equals(SIMD); 2189 assert !src.equals(sp); 2190 fcvtCpuFpuInstruction(SCVTF, dst, src, floatFromSize(targetSize), generalFromSize(srcSize)); 2191 } 2192 2193 private void fcvtCpuFpuInstruction(Instruction instr, Register dst, Register src, InstructionType type1, InstructionType type2) { 2194 emitInt(type1.encoding | type2.encoding | instr.encoding | FpConvertOp | rd(dst) | rs1(src)); 2195 } 2196 2197 /* Floating-point Round to Integral (5.7.5) */ 2198 2199 /** 2200 * Rounds floating-point to integral. Rounds towards zero. 2201 * 2202 * @param size register size. 2203 * @param dst floating point register. May not be null. 2204 * @param src floating point register. May not be null. 2205 */ 2206 protected void frintz(int size, Register dst, Register src) { 2207 fpDataProcessing1Source(FRINTZ, dst, src, floatFromSize(size)); 2208 } 2209 2210 /* Floating-point Arithmetic (1 source) (5.7.6) */ 2211 2212 /** 2213 * dst = |src|. 2214 * 2215 * @param size register size. 2216 * @param dst floating point register. May not be null. 2217 * @param src floating point register. May not be null. 2218 */ 2219 public void fabs(int size, Register dst, Register src) { 2220 fpDataProcessing1Source(FABS, dst, src, floatFromSize(size)); 2221 } 2222 2223 /** 2224 * dst = -neg. 2225 * 2226 * @param size register size. 2227 * @param dst floating point register. May not be null. 2228 * @param src floating point register. May not be null. 2229 */ 2230 public void fneg(int size, Register dst, Register src) { 2231 fpDataProcessing1Source(FNEG, dst, src, floatFromSize(size)); 2232 } 2233 2234 /** 2235 * dst = Sqrt(src). 2236 * 2237 * @param size register size. 2238 * @param dst floating point register. May not be null. 2239 * @param src floating point register. May not be null. 2240 */ 2241 public void fsqrt(int size, Register dst, Register src) { 2242 fpDataProcessing1Source(FSQRT, dst, src, floatFromSize(size)); 2243 } 2244 2245 private void fpDataProcessing1Source(Instruction instr, Register dst, Register src, InstructionType type) { 2246 assert dst.getRegisterCategory().equals(SIMD); 2247 assert src.getRegisterCategory().equals(SIMD); 2248 emitInt(type.encoding | instr.encoding | Fp1SourceOp | rd(dst) | rs1(src)); 2249 } 2250 2251 /* Floating-point Arithmetic (2 source) (5.7.7) */ 2252 2253 /** 2254 * dst = src1 + src2. 2255 * 2256 * @param size register size. 2257 * @param dst floating point register. May not be null. 2258 * @param src1 floating point register. May not be null. 2259 * @param src2 floating point register. May not be null. 2260 */ 2261 public void fadd(int size, Register dst, Register src1, Register src2) { 2262 fpDataProcessing2Source(FADD, dst, src1, src2, floatFromSize(size)); 2263 } 2264 2265 /** 2266 * dst = src1 - src2. 2267 * 2268 * @param size register size. 2269 * @param dst floating point register. May not be null. 2270 * @param src1 floating point register. May not be null. 2271 * @param src2 floating point register. May not be null. 2272 */ 2273 public void fsub(int size, Register dst, Register src1, Register src2) { 2274 fpDataProcessing2Source(FSUB, dst, src1, src2, floatFromSize(size)); 2275 } 2276 2277 /** 2278 * dst = src1 * src2. 2279 * 2280 * @param size register size. 2281 * @param dst floating point register. May not be null. 2282 * @param src1 floating point register. May not be null. 2283 * @param src2 floating point register. May not be null. 2284 */ 2285 public void fmul(int size, Register dst, Register src1, Register src2) { 2286 fpDataProcessing2Source(FMUL, dst, src1, src2, floatFromSize(size)); 2287 } 2288 2289 /** 2290 * dst = src1 / src2. 2291 * 2292 * @param size register size. 2293 * @param dst floating point register. May not be null. 2294 * @param src1 floating point register. May not be null. 2295 * @param src2 floating point register. May not be null. 2296 */ 2297 public void fdiv(int size, Register dst, Register src1, Register src2) { 2298 fpDataProcessing2Source(FDIV, dst, src1, src2, floatFromSize(size)); 2299 } 2300 2301 private void fpDataProcessing2Source(Instruction instr, Register dst, Register src1, Register src2, InstructionType type) { 2302 assert dst.getRegisterCategory().equals(SIMD); 2303 assert src1.getRegisterCategory().equals(SIMD); 2304 assert src2.getRegisterCategory().equals(SIMD); 2305 emitInt(type.encoding | instr.encoding | Fp2SourceOp | rd(dst) | rs1(src1) | rs2(src2)); 2306 } 2307 2308 /* Floating-point Multiply-Add (5.7.9) */ 2309 2310 /** 2311 * dst = src1 * src2 + src3. 2312 * 2313 * @param size register size. 2314 * @param dst floating point register. May not be null. 2315 * @param src1 floating point register. May not be null. 2316 * @param src2 floating point register. May not be null. 2317 * @param src3 floating point register. May not be null. 2318 */ 2319 protected void fmadd(int size, Register dst, Register src1, Register src2, Register src3) { 2320 fpDataProcessing3Source(FMADD, dst, src1, src2, src3, floatFromSize(size)); 2321 } 2322 2323 /** 2324 * dst = src3 - src1 * src2. 2325 * 2326 * @param size register size. 2327 * @param dst floating point register. May not be null. 2328 * @param src1 floating point register. May not be null. 2329 * @param src2 floating point register. May not be null. 2330 * @param src3 floating point register. May not be null. 2331 */ 2332 protected void fmsub(int size, Register dst, Register src1, Register src2, Register src3) { 2333 fpDataProcessing3Source(FMSUB, dst, src1, src2, src3, floatFromSize(size)); 2334 } 2335 2336 private void fpDataProcessing3Source(Instruction instr, Register dst, Register src1, Register src2, Register src3, InstructionType type) { 2337 assert dst.getRegisterCategory().equals(SIMD); 2338 assert src1.getRegisterCategory().equals(SIMD); 2339 assert src2.getRegisterCategory().equals(SIMD); 2340 assert src3.getRegisterCategory().equals(SIMD); 2341 emitInt(type.encoding | instr.encoding | Fp3SourceOp | rd(dst) | rs1(src1) | rs2(src2) | rs3(src3)); 2342 } 2343 2344 /* Floating-point Comparison (5.7.10) */ 2345 2346 /** 2347 * Compares src1 to src2. 2348 * 2349 * @param size register size. 2350 * @param src1 floating point register. May not be null. 2351 * @param src2 floating point register. May not be null. 2352 */ 2353 public void fcmp(int size, Register src1, Register src2) { 2354 assert src1.getRegisterCategory().equals(SIMD); 2355 assert src2.getRegisterCategory().equals(SIMD); 2356 InstructionType type = floatFromSize(size); 2357 emitInt(type.encoding | FCMP.encoding | FpCmpOp | rs1(src1) | rs2(src2)); 2358 } 2359 2360 /** 2361 * Conditional compare. NZCV = fcmp(src1, src2) if condition else uimm4. 2362 * 2363 * @param size register size. 2364 * @param src1 floating point register. May not be null. 2365 * @param src2 floating point register. May not be null. 2366 * @param uimm4 condition flags that are used if condition is false. 2367 * @param condition every condition allowed. May not be null. 2368 */ 2369 public void fccmp(int size, Register src1, Register src2, int uimm4, ConditionFlag condition) { 2370 assert NumUtil.isUnsignedNbit(4, uimm4); 2371 assert src1.getRegisterCategory().equals(SIMD); 2372 assert src2.getRegisterCategory().equals(SIMD); 2373 InstructionType type = floatFromSize(size); 2374 emitInt(type.encoding | FCCMP.encoding | uimm4 | condition.encoding << ConditionalConditionOffset | rs1(src1) | rs2(src2)); 2375 } 2376 2377 /** 2378 * Compare register to 0.0 . 2379 * 2380 * @param size register size. 2381 * @param src floating point register. May not be null. 2382 */ 2383 public void fcmpZero(int size, Register src) { 2384 assert src.getRegisterCategory().equals(SIMD); 2385 InstructionType type = floatFromSize(size); 2386 emitInt(type.encoding | FCMPZERO.encoding | FpCmpOp | rs1(src)); 2387 } 2388 2389 /* Floating-point Conditional Select (5.7.11) */ 2390 2391 /** 2392 * Conditional select. dst = src1 if condition else src2. 2393 * 2394 * @param size register size. 2395 * @param dst floating point register. May not be null. 2396 * @param src1 floating point register. May not be null. 2397 * @param src2 floating point register. May not be null. 2398 * @param condition every condition allowed. May not be null. 2399 */ 2400 protected void fcsel(int size, Register dst, Register src1, Register src2, ConditionFlag condition) { 2401 assert dst.getRegisterCategory().equals(SIMD); 2402 assert src1.getRegisterCategory().equals(SIMD); 2403 assert src2.getRegisterCategory().equals(SIMD); 2404 InstructionType type = floatFromSize(size); 2405 emitInt(type.encoding | FCSEL.encoding | rd(dst) | rs1(src1) | rs2(src2) | condition.encoding << ConditionalConditionOffset); 2406 } 2407 2408 /* Debug exceptions (5.9.1.2) */ 2409 2410 /** 2411 * Halting mode software breakpoint: Enters halting mode debug state if enabled, else treated as 2412 * UNALLOCATED instruction. 2413 * 2414 * @param uimm16 Arbitrary 16-bit unsigned payload. 2415 */ 2416 protected void hlt(int uimm16) { 2417 exceptionInstruction(HLT, uimm16); 2418 } 2419 2420 /** 2421 * Monitor mode software breakpoint: exception routed to a debug monitor executing in a higher 2422 * exception level. 2423 * 2424 * @param uimm16 Arbitrary 16-bit unsigned payload. 2425 */ 2426 protected void brk(int uimm16) { 2427 exceptionInstruction(BRK, uimm16); 2428 } 2429 2430 private void exceptionInstruction(Instruction instr, int uimm16) { 2431 assert NumUtil.isUnsignedNbit(16, uimm16); 2432 emitInt(instr.encoding | ExceptionOp | uimm16 << SystemImmediateOffset); 2433 } 2434 2435 /* Architectural hints (5.9.4) */ 2436 public enum SystemHint { 2437 NOP(0x0), 2438 YIELD(0x1), 2439 WFE(0x2), 2440 WFI(0x3), 2441 SEV(0x4), 2442 SEVL(0x5); 2443 2444 private final int encoding; 2445 2446 SystemHint(int encoding) { 2447 this.encoding = encoding; 2448 } 2449 } 2450 2451 /** 2452 * Architectural hints. 2453 * 2454 * @param hint Can be any of the defined hints. May not be null. 2455 */ 2456 protected void hint(SystemHint hint) { 2457 emitInt(HINT.encoding | hint.encoding << SystemImmediateOffset); 2458 } 2459 2460 /** 2461 * Clear Exclusive: clears the local record of the executing processor that an address has had a 2462 * request for an exclusive access. 2463 */ 2464 protected void clrex() { 2465 emitInt(CLREX.encoding); 2466 } 2467 2468 /** 2469 * Possible barrier definitions for Aarch64. LOAD_LOAD and LOAD_STORE map to the same underlying 2470 * barrier. 2471 * 2472 * We only need synchronization across the inner shareable domain (see B2-90 in the Reference 2473 * documentation). 2474 */ 2475 public enum BarrierKind { 2476 LOAD_LOAD(0x9, "ISHLD"), 2477 LOAD_STORE(0x9, "ISHLD"), 2478 STORE_STORE(0xA, "ISHST"), 2479 ANY_ANY(0xB, "ISH"); 2480 2481 public final int encoding; 2482 public final String optionName; 2483 2484 BarrierKind(int encoding, String optionName) { 2485 this.encoding = encoding; 2486 this.optionName = optionName; 2487 } 2488 } 2489 2490 /** 2491 * Data Memory Barrier. 2492 * 2493 * @param barrierKind barrier that is issued. May not be null. 2494 */ 2495 public void dmb(BarrierKind barrierKind) { 2496 emitInt(DMB.encoding | BarrierOp | barrierKind.encoding << BarrierKindOffset); 2497 } 2498 2499 }