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