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