| /* |
| * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| package org.graalvm.compiler.asm.aarch64; |
| |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.ADD; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.ADDS; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.ADR; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.AND; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.ANDS; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.ASRV; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.BFM; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.BIC; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.BICS; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.BLR; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.BR; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.BRK; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.CLREX; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.CLS; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.CLZ; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.CSEL; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.CSINC; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.CSNEG; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.DMB; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.EON; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.EOR; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.EXTR; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FABS; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FADD; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FCCMP; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FCMP; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FCMPZERO; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FCSEL; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FCVTDS; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FCVTSD; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FCVTZS; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FDIV; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FMADD; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FMOV; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FMSUB; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FMUL; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FNEG; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FRINTZ; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FSQRT; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FSUB; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.HINT; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.HLT; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.LDAR; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.LDAXR; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.LDP; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.LDR; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.LDRS; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.LDXR; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.LSLV; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.LSRV; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.MADD; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.MOVK; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.MOVN; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.MOVZ; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.MSUB; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.ORN; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.ORR; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.RBIT; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.RET; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.REVW; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.REVX; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.RORV; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.SBFM; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.SCVTF; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.SDIV; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.STLR; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.STLXR; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.STP; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.STR; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.STXR; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.SUB; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.SUBS; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.UBFM; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.UDIV; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.InstructionType.FP32; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.InstructionType.FP64; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.InstructionType.General32; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.InstructionType.General64; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.InstructionType.floatFromSize; |
| import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.InstructionType.generalFromSize; |
| import static jdk.vm.ci.aarch64.AArch64.CPU; |
| import static jdk.vm.ci.aarch64.AArch64.SIMD; |
| import static jdk.vm.ci.aarch64.AArch64.r0; |
| import static jdk.vm.ci.aarch64.AArch64.sp; |
| import static jdk.vm.ci.aarch64.AArch64.zr; |
| |
| import java.util.Arrays; |
| |
| import org.graalvm.compiler.asm.Assembler; |
| import org.graalvm.compiler.asm.NumUtil; |
| import org.graalvm.compiler.asm.aarch64.AArch64Address.AddressingMode; |
| import org.graalvm.compiler.debug.GraalError; |
| |
| import jdk.vm.ci.code.Register; |
| import jdk.vm.ci.code.TargetDescription; |
| |
| public abstract class AArch64Assembler extends Assembler { |
| |
| public static class LogicalImmediateTable { |
| |
| private static final Immediate[] IMMEDIATE_TABLE = buildImmediateTable(); |
| |
| private static final int ImmediateOffset = 10; |
| private static final int ImmediateRotateOffset = 16; |
| private static final int ImmediateSizeOffset = 22; |
| |
| /** |
| * Specifies whether immediate can be represented in all cases (YES), as a 64bit instruction |
| * (SIXTY_FOUR_BIT_ONLY) or not at all (NO). |
| */ |
| enum Representable { |
| YES, |
| SIXTY_FOUR_BIT_ONLY, |
| NO |
| } |
| |
| /** |
| * Tests whether an immediate can be encoded for logical instructions. |
| * |
| * @param is64bit if true immediate is considered a 64-bit pattern. If false we may use a |
| * 64-bit instruction to load the 32-bit pattern into a register. |
| * @return enum specifying whether immediate can be used for 32- and 64-bit logical |
| * instructions ({@code #Representable.YES}), for 64-bit instructions only ( |
| * {@link Representable#SIXTY_FOUR_BIT_ONLY}) or not at all ( |
| * {@link Representable#NO}). |
| */ |
| public static Representable isRepresentable(boolean is64bit, long immediate) { |
| int pos = getLogicalImmTablePos(is64bit, immediate); |
| if (pos < 0) { |
| // if 32bit instruction we can try again as 64bit immediate which may succeed. |
| // i.e. 0xffffffff fails as a 32bit immediate but works as 64bit one. |
| if (!is64bit) { |
| assert NumUtil.isUnsignedNbit(32, immediate); |
| pos = getLogicalImmTablePos(true, immediate); |
| return pos >= 0 ? Representable.SIXTY_FOUR_BIT_ONLY : Representable.NO; |
| } |
| return Representable.NO; |
| } |
| Immediate imm = IMMEDIATE_TABLE[pos]; |
| return imm.only64bit() ? Representable.SIXTY_FOUR_BIT_ONLY : Representable.YES; |
| } |
| |
| public static Representable isRepresentable(int immediate) { |
| return isRepresentable(false, immediate & 0xFFFF_FFFFL); |
| } |
| |
| public static int getLogicalImmEncoding(boolean is64bit, long value) { |
| int pos = getLogicalImmTablePos(is64bit, value); |
| assert pos >= 0 : "Value cannot be represented as logical immediate: " + value + ", is64bit=" + is64bit; |
| Immediate imm = IMMEDIATE_TABLE[pos]; |
| assert is64bit || !imm.only64bit() : "Immediate can only be represented for 64bit, but 32bit instruction specified"; |
| return IMMEDIATE_TABLE[pos].encoding; |
| } |
| |
| /** |
| * @param is64bit if true also allow 64-bit only encodings to be returned. |
| * @return If positive the return value is the position into the IMMEDIATE_TABLE for the |
| * given immediate, if negative the immediate cannot be encoded. |
| */ |
| private static int getLogicalImmTablePos(boolean is64bit, long value) { |
| Immediate imm; |
| if (!is64bit) { |
| // 32bit instructions can only have 32bit immediates. |
| if (!NumUtil.isUnsignedNbit(32, value)) { |
| return -1; |
| } |
| // If we have a 32bit instruction (and therefore immediate) we have to duplicate it |
| // across 64bit to find it in the table. |
| imm = new Immediate(value << 32 | value); |
| } else { |
| imm = new Immediate(value); |
| } |
| int pos = Arrays.binarySearch(IMMEDIATE_TABLE, imm); |
| if (pos < 0) { |
| return -1; |
| } |
| if (!is64bit && IMMEDIATE_TABLE[pos].only64bit()) { |
| return -1; |
| } |
| return pos; |
| } |
| |
| /** |
| * To quote 5.4.2: [..] an immediate is a 32 or 64 bit pattern viewed as a vector of |
| * identical elements of size e = 2, 4, 8, 16, 32 or (in the case of bimm64) 64 bits. Each |
| * element contains the same sub-pattern: a single run of 1 to e-1 non-zero bits, rotated by |
| * 0 to e-1 bits. It is encoded in the following: 10-16: rotation amount (6bit) starting |
| * from 1s in the LSB (i.e. 0111->1011->1101->1110) 16-22: This stores a combination of the |
| * number of set bits and the pattern size. The pattern size is encoded as follows (x is |
| * used to store the number of 1 bits - 1) e pattern 2 1111xx 4 1110xx 8 110xxx 16 10xxxx 32 |
| * 0xxxxx 64 xxxxxx 22: if set we have an instruction with 64bit pattern? |
| */ |
| private static final class Immediate implements Comparable<Immediate> { |
| public final long imm; |
| public final int encoding; |
| |
| Immediate(long imm, boolean is64, int s, int r) { |
| this.imm = imm; |
| this.encoding = computeEncoding(is64, s, r); |
| } |
| |
| // Used to be able to binary search for an immediate in the table. |
| Immediate(long imm) { |
| this(imm, false, 0, 0); |
| } |
| |
| /** |
| * Returns true if this pattern is only representable as 64bit. |
| */ |
| public boolean only64bit() { |
| return (encoding & (1 << ImmediateSizeOffset)) != 0; |
| } |
| |
| private static int computeEncoding(boolean is64, int s, int r) { |
| int sf = is64 ? 1 : 0; |
| return sf << ImmediateSizeOffset | r << ImmediateRotateOffset | s << ImmediateOffset; |
| } |
| |
| @Override |
| public int compareTo(Immediate o) { |
| return Long.compare(imm, o.imm); |
| } |
| } |
| |
| private static Immediate[] buildImmediateTable() { |
| final int nrImmediates = 5334; |
| final Immediate[] table = new Immediate[nrImmediates]; |
| int nrImms = 0; |
| for (int logE = 1; logE <= 6; logE++) { |
| int e = 1 << logE; |
| long mask = NumUtil.getNbitNumberLong(e); |
| for (int nrOnes = 1; nrOnes < e; nrOnes++) { |
| long val = (1L << nrOnes) - 1; |
| // r specifies how much we rotate the value |
| for (int r = 0; r < e; r++) { |
| long immediate = (val >>> r | val << (e - r)) & mask; |
| // Duplicate pattern to fill whole 64bit range. |
| switch (logE) { |
| case 1: |
| immediate |= immediate << 2; |
| immediate |= immediate << 4; |
| immediate |= immediate << 8; |
| immediate |= immediate << 16; |
| immediate |= immediate << 32; |
| break; |
| case 2: |
| immediate |= immediate << 4; |
| immediate |= immediate << 8; |
| immediate |= immediate << 16; |
| immediate |= immediate << 32; |
| break; |
| case 3: |
| immediate |= immediate << 8; |
| immediate |= immediate << 16; |
| immediate |= immediate << 32; |
| break; |
| case 4: |
| immediate |= immediate << 16; |
| immediate |= immediate << 32; |
| break; |
| case 5: |
| immediate |= immediate << 32; |
| break; |
| } |
| // 5 - logE can underflow to -1, but we shift this bogus result |
| // out of the masked area. |
| int sizeEncoding = (1 << (5 - logE)) - 1; |
| int s = ((sizeEncoding << (logE + 1)) & 0x3f) | (nrOnes - 1); |
| table[nrImms++] = new Immediate(immediate, /* is64bit */e == 64, s, r); |
| } |
| } |
| } |
| Arrays.sort(table); |
| assert nrImms == nrImmediates : nrImms + " instead of " + nrImmediates + " in table."; |
| assert checkDuplicates(table) : "Duplicate values in table."; |
| return table; |
| } |
| |
| private static boolean checkDuplicates(Immediate[] table) { |
| for (int i = 0; i < table.length - 1; i++) { |
| if (table[i].imm >= table[i + 1].imm) { |
| return false; |
| } |
| } |
| return true; |
| } |
| } |
| |
| private static final int RdOffset = 0; |
| private static final int Rs1Offset = 5; |
| private static final int Rs2Offset = 16; |
| private static final int Rs3Offset = 10; |
| private static final int RtOffset = 0; |
| private static final int RnOffset = 5; |
| private static final int Rt2Offset = 10; |
| |
| /* Helper functions */ |
| private static int rd(Register reg) { |
| return reg.encoding << RdOffset; |
| } |
| |
| private static int rs1(Register reg) { |
| return reg.encoding << Rs1Offset; |
| } |
| |
| private static int rs2(Register reg) { |
| return reg.encoding << Rs2Offset; |
| } |
| |
| private static int rs3(Register reg) { |
| return reg.encoding << Rs3Offset; |
| } |
| |
| private static int rt(Register reg) { |
| return reg.encoding << RtOffset; |
| } |
| |
| private static int rt2(Register reg) { |
| return reg.encoding << Rt2Offset; |
| } |
| |
| private static int rn(Register reg) { |
| return reg.encoding << RnOffset; |
| } |
| |
| /** |
| * Enumeration of all different instruction kinds: General32/64 are the general instructions |
| * (integer, branch, etc.), for 32-, respectively 64-bit operands. FP32/64 is the encoding for |
| * the 32/64bit float operations |
| */ |
| protected enum InstructionType { |
| General32(0b00 << 30, 32, true), |
| General64(0b10 << 30, 64, true), |
| FP32(0x00000000, 32, false), |
| FP64(0x00400000, 64, false); |
| |
| public final int encoding; |
| public final int width; |
| public final boolean isGeneral; |
| |
| InstructionType(int encoding, int width, boolean isGeneral) { |
| this.encoding = encoding; |
| this.width = width; |
| this.isGeneral = isGeneral; |
| } |
| |
| public static InstructionType generalFromSize(int size) { |
| assert size == 32 || size == 64; |
| return size == 32 ? General32 : General64; |
| } |
| |
| public static InstructionType floatFromSize(int size) { |
| assert size == 32 || size == 64; |
| return size == 32 ? FP32 : FP64; |
| } |
| |
| } |
| |
| private static final int ImmediateOffset = 10; |
| private static final int ImmediateRotateOffset = 16; |
| private static final int ImmediateSizeOffset = 22; |
| private static final int ExtendTypeOffset = 13; |
| |
| private static final int AddSubImmOp = 0x11000000; |
| private static final int AddSubShift12 = 0b01 << 22; |
| private static final int AddSubSetFlag = 0x20000000; |
| |
| private static final int LogicalImmOp = 0x12000000; |
| |
| private static final int MoveWideImmOp = 0x12800000; |
| private static final int MoveWideImmOffset = 5; |
| private static final int MoveWideShiftOffset = 21; |
| |
| private static final int BitfieldImmOp = 0x13000000; |
| |
| private static final int AddSubShiftedOp = 0x0B000000; |
| private static final int ShiftTypeOffset = 22; |
| |
| private static final int AddSubExtendedOp = 0x0B200000; |
| |
| private static final int MulOp = 0x1B000000; |
| private static final int DataProcessing1SourceOp = 0x5AC00000; |
| private static final int DataProcessing2SourceOp = 0x1AC00000; |
| |
| private static final int Fp1SourceOp = 0x1E204000; |
| private static final int Fp2SourceOp = 0x1E200800; |
| private static final int Fp3SourceOp = 0x1F000000; |
| |
| private static final int FpConvertOp = 0x1E200000; |
| private static final int FpImmOp = 0x1E201000; |
| private static final int FpImmOffset = 13; |
| |
| private static final int FpCmpOp = 0x1E202000; |
| |
| private static final int PcRelImmHiOffset = 5; |
| private static final int PcRelImmLoOffset = 29; |
| |
| private static final int PcRelImmOp = 0x10000000; |
| |
| private static final int UnconditionalBranchImmOp = 0x14000000; |
| private static final int UnconditionalBranchRegOp = 0xD6000000; |
| private static final int CompareBranchOp = 0x34000000; |
| |
| private static final int ConditionalBranchImmOffset = 5; |
| |
| private static final int ConditionalSelectOp = 0x1A800000; |
| private static final int ConditionalConditionOffset = 12; |
| |
| private static final int LoadStoreScaledOp = 0b111_0_01_00 << 22; |
| private static final int LoadStoreUnscaledOp = 0b111_0_00_00 << 22; |
| |
| private static final int LoadStoreRegisterOp = 0b111_0_00_00_1 << 21 | 0b10 << 10; |
| |
| private static final int LoadLiteralOp = 0x18000000; |
| |
| private static final int LoadStorePostIndexedOp = 0b111_0_00_00_0 << 21 | 0b01 << 10; |
| private static final int LoadStorePreIndexedOp = 0b111_0_00_00_0 << 21 | 0b11 << 10; |
| |
| private static final int LoadStoreUnscaledImmOffset = 12; |
| private static final int LoadStoreScaledImmOffset = 10; |
| private static final int LoadStoreScaledRegOffset = 12; |
| private static final int LoadStoreIndexedImmOffset = 12; |
| private static final int LoadStoreTransferSizeOffset = 30; |
| private static final int LoadStoreFpFlagOffset = 26; |
| private static final int LoadLiteralImmeOffset = 5; |
| |
| private static final int LoadStorePairOp = 0b101_0_010 << 23; |
| @SuppressWarnings("unused") private static final int LoadStorePairPostIndexOp = 0b101_0_001 << 23; |
| @SuppressWarnings("unused") private static final int LoadStorePairPreIndexOp = 0b101_0_011 << 23; |
| private static final int LoadStorePairImm7Offset = 15; |
| |
| private static final int LogicalShiftOp = 0x0A000000; |
| |
| private static final int ExceptionOp = 0xD4000000; |
| private static final int SystemImmediateOffset = 5; |
| |
| @SuppressWarnings("unused") private static final int SimdImmediateOffset = 16; |
| |
| private static final int BarrierOp = 0xD503301F; |
| private static final int BarrierKindOffset = 8; |
| |
| /** |
| * Encoding for all instructions. |
| */ |
| public enum Instruction { |
| BCOND(0x54000000), |
| CBNZ(0x01000000), |
| CBZ(0x00000000), |
| |
| B(0x00000000), |
| BL(0x80000000), |
| BR(0x001F0000), |
| BLR(0x003F0000), |
| RET(0x005F0000), |
| |
| LDR(0x00000000), |
| LDRS(0x00800000), |
| LDXR(0x081f7c00), |
| LDAR(0x8dffc00), |
| LDAXR(0x85ffc00), |
| |
| STR(0x00000000), |
| STXR(0x08007c00), |
| STLR(0x089ffc00), |
| STLXR(0x0800fc00), |
| |
| LDP(0b1 << 22), |
| STP(0b0 << 22), |
| |
| ADR(0x00000000), |
| ADRP(0x80000000), |
| |
| ADD(0x00000000), |
| ADDS(ADD.encoding | AddSubSetFlag), |
| SUB(0x40000000), |
| SUBS(SUB.encoding | AddSubSetFlag), |
| |
| NOT(0x00200000), |
| AND(0x00000000), |
| BIC(AND.encoding | NOT.encoding), |
| ORR(0x20000000), |
| ORN(ORR.encoding | NOT.encoding), |
| EOR(0x40000000), |
| EON(EOR.encoding | NOT.encoding), |
| ANDS(0x60000000), |
| BICS(ANDS.encoding | NOT.encoding), |
| |
| ASRV(0x00002800), |
| RORV(0x00002C00), |
| LSRV(0x00002400), |
| LSLV(0x00002000), |
| |
| CLS(0x00001400), |
| CLZ(0x00001000), |
| RBIT(0x00000000), |
| REVX(0x00000C00), |
| REVW(0x00000800), |
| |
| MOVN(0x00000000), |
| MOVZ(0x40000000), |
| MOVK(0x60000000), |
| |
| CSEL(0x00000000), |
| CSNEG(0x40000400), |
| CSINC(0x00000400), |
| |
| BFM(0x20000000), |
| SBFM(0x00000000), |
| UBFM(0x40000000), |
| EXTR(0x13800000), |
| |
| MADD(0x00000000), |
| MSUB(0x00008000), |
| SDIV(0x00000C00), |
| UDIV(0x00000800), |
| |
| FMOV(0x00000000), |
| FMOVCPU2FPU(0x00070000), |
| FMOVFPU2CPU(0x00060000), |
| |
| FCVTDS(0x00028000), |
| FCVTSD(0x00020000), |
| |
| FCVTZS(0x00180000), |
| SCVTF(0x00020000), |
| |
| FABS(0x00008000), |
| FSQRT(0x00018000), |
| FNEG(0x00010000), |
| |
| FRINTZ(0x00058000), |
| |
| FADD(0x00002000), |
| FSUB(0x00003000), |
| FMUL(0x00000000), |
| FDIV(0x00001000), |
| FMAX(0x00004000), |
| FMIN(0x00005000), |
| |
| FMADD(0x00000000), |
| FMSUB(0x00008000), |
| |
| FCMP(0x00000000), |
| FCMPZERO(0x00000008), |
| FCCMP(0x1E200400), |
| FCSEL(0x1E200C00), |
| |
| INS(0x4e081c00), |
| UMOV(0x4e083c00), |
| |
| CNT(0xe205800), |
| USRA(0x6f001400), |
| |
| HLT(0x00400000), |
| BRK(0x00200000), |
| |
| CLREX(0xd5033f5f), |
| HINT(0xD503201F), |
| DMB(0x000000A0), |
| |
| BLR_NATIVE(0xc0000000); |
| |
| public final int encoding; |
| |
| Instruction(int encoding) { |
| this.encoding = encoding; |
| } |
| |
| } |
| |
| public enum ShiftType { |
| LSL(0), |
| LSR(1), |
| ASR(2), |
| ROR(3); |
| |
| public final int encoding; |
| |
| ShiftType(int encoding) { |
| this.encoding = encoding; |
| } |
| } |
| |
| public enum ExtendType { |
| UXTB(0), |
| UXTH(1), |
| UXTW(2), |
| UXTX(3), |
| SXTB(4), |
| SXTH(5), |
| SXTW(6), |
| SXTX(7); |
| |
| public final int encoding; |
| |
| ExtendType(int encoding) { |
| this.encoding = encoding; |
| } |
| } |
| |
| /** |
| * Condition Flags for branches. See 4.3 |
| */ |
| public enum ConditionFlag { |
| // Integer | Floating-point meanings |
| /** Equal | Equal. */ |
| EQ(0x0), |
| |
| /** Not Equal | Not equal or unordered. */ |
| NE(0x1), |
| |
| /** Unsigned Higher or Same | Greater than, equal or unordered. */ |
| HS(0x2), |
| |
| /** Unsigned lower | less than. */ |
| LO(0x3), |
| |
| /** Minus (negative) | less than. */ |
| MI(0x4), |
| |
| /** Plus (positive or zero) | greater than, equal or unordered. */ |
| PL(0x5), |
| |
| /** Overflow set | unordered. */ |
| VS(0x6), |
| |
| /** Overflow clear | ordered. */ |
| VC(0x7), |
| |
| /** Unsigned higher | greater than or unordered. */ |
| HI(0x8), |
| |
| /** Unsigned lower or same | less than or equal. */ |
| LS(0x9), |
| |
| /** Signed greater than or equal | greater than or equal. */ |
| GE(0xA), |
| |
| /** Signed less than | less than or unordered. */ |
| LT(0xB), |
| |
| /** Signed greater than | greater than. */ |
| GT(0xC), |
| |
| /** Signed less than or equal | less than, equal or unordered. */ |
| LE(0xD), |
| |
| /** Always | always. */ |
| AL(0xE), |
| |
| /** Always | always (identical to AL, just to have valid 0b1111 encoding). */ |
| NV(0xF); |
| |
| public final int encoding; |
| |
| ConditionFlag(int encoding) { |
| this.encoding = encoding; |
| } |
| |
| /** |
| * @return ConditionFlag specified by decoding. |
| */ |
| public static ConditionFlag fromEncoding(int encoding) { |
| return values()[encoding]; |
| } |
| |
| public ConditionFlag negate() { |
| switch (this) { |
| case EQ: |
| return NE; |
| case NE: |
| return EQ; |
| case HS: |
| return LO; |
| case LO: |
| return HS; |
| case MI: |
| return PL; |
| case PL: |
| return MI; |
| case VS: |
| return VC; |
| case VC: |
| return VS; |
| case HI: |
| return LS; |
| case LS: |
| return HI; |
| case GE: |
| return LT; |
| case LT: |
| return GE; |
| case GT: |
| return LE; |
| case LE: |
| return GT; |
| case AL: |
| case NV: |
| default: |
| throw GraalError.shouldNotReachHere(); |
| } |
| } |
| } |
| |
| public AArch64Assembler(TargetDescription target) { |
| super(target); |
| } |
| |
| /* Conditional Branch (5.2.1) */ |
| |
| /** |
| * Branch conditionally. |
| * |
| * @param condition may not be null. |
| * @param imm21 Signed 21-bit offset, has to be word aligned. |
| */ |
| protected void b(ConditionFlag condition, int imm21) { |
| b(condition, imm21, -1); |
| } |
| |
| /** |
| * Branch conditionally. Inserts instruction into code buffer at pos. |
| * |
| * @param condition may not be null. |
| * @param imm21 Signed 21-bit offset, has to be word aligned. |
| * @param pos Position at which instruction is inserted into buffer. -1 means insert at end. |
| */ |
| protected void b(ConditionFlag condition, int imm21, int pos) { |
| if (pos == -1) { |
| emitInt(Instruction.BCOND.encoding | getConditionalBranchImm(imm21) | condition.encoding); |
| } else { |
| emitInt(Instruction.BCOND.encoding | getConditionalBranchImm(imm21) | condition.encoding, pos); |
| } |
| } |
| |
| /** |
| * Compare register and branch if non-zero. |
| * |
| * @param reg general purpose register. May not be null, zero-register or stackpointer. |
| * @param size Instruction size in bits. Should be either 32 or 64. |
| * @param imm21 Signed 21-bit offset, has to be word aligned. |
| */ |
| protected void cbnz(int size, Register reg, int imm21) { |
| conditionalBranchInstruction(reg, imm21, generalFromSize(size), Instruction.CBNZ, -1); |
| } |
| |
| /** |
| * Compare register and branch if non-zero. |
| * |
| * @param reg general purpose register. May not be null, zero-register or stackpointer. |
| * @param size Instruction size in bits. Should be either 32 or 64. |
| * @param imm21 Signed 21-bit offset, has to be word aligned. |
| * @param pos Position at which instruction is inserted into buffer. -1 means insert at end. |
| */ |
| protected void cbnz(int size, Register reg, int imm21, int pos) { |
| conditionalBranchInstruction(reg, imm21, generalFromSize(size), Instruction.CBNZ, pos); |
| } |
| |
| /** |
| * Compare and branch if zero. |
| * |
| * @param reg general purpose register. May not be null, zero-register or stackpointer. |
| * @param size Instruction size in bits. Should be either 32 or 64. |
| * @param imm21 Signed 21-bit offset, has to be word aligned. |
| */ |
| protected void cbz(int size, Register reg, int imm21) { |
| conditionalBranchInstruction(reg, imm21, generalFromSize(size), Instruction.CBZ, -1); |
| } |
| |
| /** |
| * Compare register and branch if zero. |
| * |
| * @param reg general purpose register. May not be null, zero-register or stackpointer. |
| * @param size Instruction size in bits. Should be either 32 or 64. |
| * @param imm21 Signed 21-bit offset, has to be word aligned. |
| * @param pos Position at which instruction is inserted into buffer. -1 means insert at end. |
| */ |
| protected void cbz(int size, Register reg, int imm21, int pos) { |
| conditionalBranchInstruction(reg, imm21, generalFromSize(size), Instruction.CBZ, pos); |
| } |
| |
| private void conditionalBranchInstruction(Register reg, int imm21, InstructionType type, Instruction instr, int pos) { |
| assert reg.getRegisterCategory().equals(CPU); |
| int instrEncoding = instr.encoding | CompareBranchOp; |
| if (pos == -1) { |
| emitInt(type.encoding | instrEncoding | getConditionalBranchImm(imm21) | rd(reg)); |
| } else { |
| emitInt(type.encoding | instrEncoding | getConditionalBranchImm(imm21) | rd(reg), pos); |
| } |
| } |
| |
| private static int getConditionalBranchImm(int imm21) { |
| assert NumUtil.isSignedNbit(21, imm21) && (imm21 & 0x3) == 0 : "Immediate has to be 21bit signed number and word aligned"; |
| int imm = (imm21 & NumUtil.getNbitNumberInt(21)) >> 2; |
| return imm << ConditionalBranchImmOffset; |
| } |
| |
| /* Unconditional Branch (immediate) (5.2.2) */ |
| |
| /** |
| * @param imm28 Signed 28-bit offset, has to be word aligned. |
| */ |
| protected void b(int imm28) { |
| unconditionalBranchImmInstruction(imm28, Instruction.B, -1); |
| } |
| |
| /** |
| * |
| * @param imm28 Signed 28-bit offset, has to be word aligned. |
| * @param pos Position where instruction is inserted into code buffer. |
| */ |
| protected void b(int imm28, int pos) { |
| unconditionalBranchImmInstruction(imm28, Instruction.B, pos); |
| } |
| |
| /** |
| * Branch and link return address to register X30. |
| * |
| * @param imm28 Signed 28-bit offset, has to be word aligned. |
| */ |
| public void bl(int imm28) { |
| unconditionalBranchImmInstruction(imm28, Instruction.BL, -1); |
| } |
| |
| private void unconditionalBranchImmInstruction(int imm28, Instruction instr, int pos) { |
| assert NumUtil.isSignedNbit(28, imm28) && (imm28 & 0x3) == 0 : "Immediate has to be 28bit signed number and word aligned"; |
| int imm = (imm28 & NumUtil.getNbitNumberInt(28)) >> 2; |
| int instrEncoding = instr.encoding | UnconditionalBranchImmOp; |
| if (pos == -1) { |
| emitInt(instrEncoding | imm); |
| } else { |
| emitInt(instrEncoding | imm, pos); |
| } |
| } |
| |
| /* Unconditional Branch (register) (5.2.3) */ |
| |
| /** |
| * Branches to address in register and writes return address into register X30. |
| * |
| * @param reg general purpose register. May not be null, zero-register or stackpointer. |
| */ |
| public void blr(Register reg) { |
| unconditionalBranchRegInstruction(BLR, reg); |
| } |
| |
| /** |
| * Branches to address in register. |
| * |
| * @param reg general purpose register. May not be null, zero-register or stackpointer. |
| */ |
| protected void br(Register reg) { |
| unconditionalBranchRegInstruction(BR, reg); |
| } |
| |
| /** |
| * Return to address in register. |
| * |
| * @param reg general purpose register. May not be null, zero-register or stackpointer. |
| */ |
| public void ret(Register reg) { |
| unconditionalBranchRegInstruction(RET, reg); |
| } |
| |
| private void unconditionalBranchRegInstruction(Instruction instr, Register reg) { |
| assert reg.getRegisterCategory().equals(CPU); |
| assert !reg.equals(zr); |
| assert !reg.equals(sp); |
| emitInt(instr.encoding | UnconditionalBranchRegOp | rs1(reg)); |
| } |
| |
| /* Load-Store Single Register (5.3.1) */ |
| |
| /** |
| * Loads a srcSize value from address into rt zero-extending it. |
| * |
| * @param srcSize size of memory read in bits. Must be 8, 16, 32 or 64. |
| * @param rt general purpose register. May not be null or stackpointer. |
| * @param address all addressing modes allowed. May not be null. |
| */ |
| public void ldr(int srcSize, Register rt, AArch64Address address) { |
| assert rt.getRegisterCategory().equals(CPU); |
| assert srcSize == 8 || srcSize == 16 || srcSize == 32 || srcSize == 64; |
| int transferSize = NumUtil.log2Ceil(srcSize / 8); |
| loadStoreInstruction(LDR, rt, address, General32, transferSize); |
| } |
| |
| /** |
| * Loads a srcSize value from address into rt sign-extending it. |
| * |
| * @param targetSize size of target register in bits. Must be 32 or 64. |
| * @param srcSize size of memory read in bits. Must be 8, 16 or 32, but may not be equivalent to |
| * targetSize. |
| * @param rt general purpose register. May not be null or stackpointer. |
| * @param address all addressing modes allowed. May not be null. |
| */ |
| protected void ldrs(int targetSize, int srcSize, Register rt, AArch64Address address) { |
| assert rt.getRegisterCategory().equals(CPU); |
| assert (srcSize == 8 || srcSize == 16 || srcSize == 32) && srcSize != targetSize; |
| int transferSize = NumUtil.log2Ceil(srcSize / 8); |
| loadStoreInstruction(LDRS, rt, address, generalFromSize(targetSize), transferSize); |
| } |
| |
| /** |
| * Stores register rt into memory pointed by address. |
| * |
| * @param destSize number of bits written to memory. Must be 8, 16, 32 or 64. |
| * @param rt general purpose register. May not be null or stackpointer. |
| * @param address all addressing modes allowed. May not be null. |
| */ |
| public void str(int destSize, Register rt, AArch64Address address) { |
| assert rt.getRegisterCategory().equals(CPU); |
| assert destSize == 8 || destSize == 16 || destSize == 32 || destSize == 64; |
| int transferSize = NumUtil.log2Ceil(destSize / 8); |
| loadStoreInstruction(STR, rt, address, General64, transferSize); |
| } |
| |
| private void loadStoreInstruction(Instruction instr, Register reg, AArch64Address address, InstructionType type, int log2TransferSize) { |
| assert log2TransferSize >= 0 && log2TransferSize < 4; |
| int transferSizeEncoding = log2TransferSize << LoadStoreTransferSizeOffset; |
| int is32Bit = type.width == 32 ? 1 << ImmediateSizeOffset : 0; |
| int isFloat = !type.isGeneral ? 1 << LoadStoreFpFlagOffset : 0; |
| int memop = instr.encoding | transferSizeEncoding | is32Bit | isFloat | rt(reg); |
| switch (address.getAddressingMode()) { |
| case IMMEDIATE_SCALED: |
| emitInt(memop | LoadStoreScaledOp | address.getImmediate() << LoadStoreScaledImmOffset | rs1(address.getBase())); |
| break; |
| case IMMEDIATE_UNSCALED: |
| emitInt(memop | LoadStoreUnscaledOp | address.getImmediate() << LoadStoreUnscaledImmOffset | rs1(address.getBase())); |
| break; |
| case BASE_REGISTER_ONLY: |
| emitInt(memop | LoadStoreScaledOp | rs1(address.getBase())); |
| break; |
| case EXTENDED_REGISTER_OFFSET: |
| case REGISTER_OFFSET: |
| ExtendType extendType = address.getAddressingMode() == AddressingMode.EXTENDED_REGISTER_OFFSET ? address.getExtendType() : ExtendType.UXTX; |
| boolean shouldScale = address.isScaled() && log2TransferSize != 0; |
| emitInt(memop | LoadStoreRegisterOp | rs2(address.getOffset()) | extendType.encoding << ExtendTypeOffset | (shouldScale ? 1 : 0) << LoadStoreScaledRegOffset | rs1(address.getBase())); |
| break; |
| case PC_LITERAL: |
| assert log2TransferSize >= 2 : "PC literal loads only works for load/stores of 32-bit and larger"; |
| transferSizeEncoding = (log2TransferSize - 2) << LoadStoreTransferSizeOffset; |
| emitInt(transferSizeEncoding | isFloat | LoadLiteralOp | rd(reg) | address.getImmediate() << LoadLiteralImmeOffset); |
| break; |
| case IMMEDIATE_POST_INDEXED: |
| emitInt(memop | LoadStorePostIndexedOp | rs1(address.getBase()) | address.getImmediate() << LoadStoreIndexedImmOffset); |
| break; |
| case IMMEDIATE_PRE_INDEXED: |
| emitInt(memop | LoadStorePreIndexedOp | rs1(address.getBase()) | address.getImmediate() << LoadStoreIndexedImmOffset); |
| break; |
| default: |
| throw GraalError.shouldNotReachHere("Unhandled addressing mode: " + address.getAddressingMode()); |
| } |
| } |
| |
| /** |
| * |
| */ |
| public void ldp(int size, Register rt, Register rt2, AArch64Address address) { |
| assert size == 32 || size == 64; |
| loadStorePairInstruction(LDP, rt, rt2, address, generalFromSize(size)); |
| } |
| |
| /** |
| * Store Pair of Registers calculates an address from a base register value and an immediate |
| * offset, and stores two 32-bit words or two 64-bit doublewords to the calculated address, from |
| * two registers. |
| */ |
| public void stp(int size, Register rt, Register rt2, AArch64Address address) { |
| assert size == 32 || size == 64; |
| loadStorePairInstruction(STP, rt, rt2, address, generalFromSize(size)); |
| } |
| |
| private void loadStorePairInstruction(Instruction instr, Register rt, Register rt2, AArch64Address address, InstructionType type) { |
| int memop = type.encoding | instr.encoding | address.getImmediate() << LoadStorePairImm7Offset | rt2(rt2) | rn(address.getBase()) | rt(rt); |
| switch (address.getAddressingMode()) { |
| case IMMEDIATE_UNSCALED: |
| emitInt(memop | LoadStorePairOp); |
| break; |
| default: |
| throw GraalError.shouldNotReachHere("Unhandled addressing mode: " + address.getAddressingMode()); |
| } |
| } |
| |
| /* Load-Store Exclusive (5.3.6) */ |
| |
| /** |
| * Load address exclusive. Natural alignment of address is required. |
| * |
| * @param size size of memory read in bits. Must be 8, 16, 32 or 64. |
| * @param rt general purpose register. May not be null or stackpointer. |
| * @param rn general purpose register. |
| */ |
| protected void ldxr(int size, Register rt, Register rn) { |
| assert size == 8 || size == 16 || size == 32 || size == 64; |
| int transferSize = NumUtil.log2Ceil(size / 8); |
| exclusiveLoadInstruction(LDXR, rt, rn, transferSize); |
| } |
| |
| /** |
| * Store address exclusive. Natural alignment of address is required. rs and rt may not point to |
| * the same register. |
| * |
| * @param size size of bits written to memory. Must be 8, 16, 32 or 64. |
| * @param rs general purpose register. Set to exclusive access status. 0 means success, |
| * everything else failure. May not be null, or stackpointer. |
| * @param rt general purpose register. May not be null or stackpointer. |
| * @param rn general purpose register. |
| */ |
| protected void stxr(int size, Register rs, Register rt, Register rn) { |
| assert size == 8 || size == 16 || size == 32 || size == 64; |
| int transferSize = NumUtil.log2Ceil(size / 8); |
| exclusiveStoreInstruction(STXR, rs, rt, rn, transferSize); |
| } |
| |
| /* Load-Acquire/Store-Release (5.3.7) */ |
| |
| /* non exclusive access */ |
| /** |
| * Load acquire. Natural alignment of address is required. |
| * |
| * @param size size of memory read in bits. Must be 8, 16, 32 or 64. |
| * @param rt general purpose register. May not be null or stackpointer. |
| * @param rn general purpose register. |
| */ |
| protected void ldar(int size, Register rt, Register rn) { |
| assert size == 8 || size == 16 || size == 32 || size == 64; |
| int transferSize = NumUtil.log2Ceil(size / 8); |
| exclusiveLoadInstruction(LDAR, rt, rn, transferSize); |
| } |
| |
| /** |
| * Store-release. Natural alignment of address is required. |
| * |
| * @param size size of bits written to memory. Must be 8, 16, 32 or 64. |
| * @param rt general purpose register. May not be null or stackpointer. |
| * @param rn general purpose register. |
| */ |
| protected void stlr(int size, Register rt, Register rn) { |
| assert size == 8 || size == 16 || size == 32 || size == 64; |
| int transferSize = NumUtil.log2Ceil(size / 8); |
| // Hack: Passing the zero-register means it is ignored when building the encoding. |
| exclusiveStoreInstruction(STLR, r0, rt, rn, transferSize); |
| } |
| |
| /* exclusive access */ |
| /** |
| * Load acquire exclusive. Natural alignment of address is required. |
| * |
| * @param size size of memory read in bits. Must be 8, 16, 32 or 64. |
| * @param rt general purpose register. May not be null or stackpointer. |
| * @param rn general purpose register. |
| */ |
| public void ldaxr(int size, Register rt, Register rn) { |
| assert size == 8 || size == 16 || size == 32 || size == 64; |
| int transferSize = NumUtil.log2Ceil(size / 8); |
| exclusiveLoadInstruction(LDAXR, rt, rn, transferSize); |
| } |
| |
| /** |
| * Store-release exclusive. Natural alignment of address is required. rs and rt may not point to |
| * the same register. |
| * |
| * @param size size of bits written to memory. Must be 8, 16, 32 or 64. |
| * @param rs general purpose register. Set to exclusive access status. 0 means success, |
| * everything else failure. May not be null, or stackpointer. |
| * @param rt general purpose register. May not be null or stackpointer. |
| * @param rn general purpose register. |
| */ |
| public void stlxr(int size, Register rs, Register rt, Register rn) { |
| assert size == 8 || size == 16 || size == 32 || size == 64; |
| int transferSize = NumUtil.log2Ceil(size / 8); |
| exclusiveStoreInstruction(STLXR, rs, rt, rn, transferSize); |
| } |
| |
| private void exclusiveLoadInstruction(Instruction instr, Register reg, Register rn, int log2TransferSize) { |
| assert log2TransferSize >= 0 && log2TransferSize < 4; |
| assert reg.getRegisterCategory().equals(CPU); |
| int transferSizeEncoding = log2TransferSize << LoadStoreTransferSizeOffset; |
| emitInt(transferSizeEncoding | instr.encoding | 1 << ImmediateSizeOffset | rn(rn) | rt(reg)); |
| } |
| |
| /** |
| * Stores data from rt into address and sets rs to the returned exclusive access status. |
| * |
| * @param rs general purpose register into which the exclusive access status is written. May not |
| * be null. |
| * @param rt general purpose register containing data to be written to memory at address. May |
| * not be null |
| * @param rn general purpose register containing the address specifying where rt is written to. |
| * @param log2TransferSize log2Ceil of memory transfer size. |
| */ |
| private void exclusiveStoreInstruction(Instruction instr, Register rs, Register rt, Register rn, int log2TransferSize) { |
| assert log2TransferSize >= 0 && log2TransferSize < 4; |
| assert rt.getRegisterCategory().equals(CPU) && rs.getRegisterCategory().equals(CPU) && !rs.equals(rt); |
| int transferSizeEncoding = log2TransferSize << LoadStoreTransferSizeOffset; |
| emitInt(transferSizeEncoding | instr.encoding | rs2(rs) | rn(rn) | rt(rt)); |
| } |
| |
| /* PC-relative Address Calculation (5.4.4) */ |
| |
| /** |
| * Address of page: sign extends 21-bit offset, shifts if left by 12 and adds it to the value of |
| * the PC with its bottom 12-bits cleared, writing the result to dst. |
| * |
| * @param dst general purpose register. May not be null, zero-register or stackpointer. |
| * @param imm Signed 33-bit offset with lower 12bits clear. |
| */ |
| // protected void adrp(Register dst, long imm) { |
| // assert (imm & NumUtil.getNbitNumberInt(12)) == 0 : "Lower 12-bit of immediate must be zero."; |
| // assert NumUtil.isSignedNbit(33, imm); |
| // addressCalculationInstruction(dst, (int) (imm >>> 12), Instruction.ADRP); |
| // } |
| |
| /** |
| * Adds a 21-bit signed offset to the program counter and writes the result to dst. |
| * |
| * @param dst general purpose register. May not be null, zero-register or stackpointer. |
| * @param imm21 Signed 21-bit offset. |
| */ |
| public void adr(Register dst, int imm21) { |
| emitInt(ADR.encoding | PcRelImmOp | rd(dst) | getPcRelativeImmEncoding(imm21)); |
| } |
| |
| public void adr(Register dst, int imm21, int pos) { |
| emitInt(ADR.encoding | PcRelImmOp | rd(dst) | getPcRelativeImmEncoding(imm21), pos); |
| } |
| |
| private static int getPcRelativeImmEncoding(int imm21) { |
| assert NumUtil.isSignedNbit(21, imm21); |
| int imm = imm21 & NumUtil.getNbitNumberInt(21); |
| // higher 19 bit |
| int immHi = (imm >> 2) << PcRelImmHiOffset; |
| // lower 2 bit |
| int immLo = (imm & 0x3) << PcRelImmLoOffset; |
| return immHi | immLo; |
| } |
| |
| /* Arithmetic (Immediate) (5.4.1) */ |
| |
| /** |
| * dst = src + aimm. |
| * |
| * @param size register size. Has to be 32 or 64. |
| * @param dst general purpose register. May not be null or zero-register. |
| * @param src general purpose register. May not be null or zero-register. |
| * @param aimm arithmetic immediate. Either unsigned 12-bit value or unsigned 24-bit value with |
| * the lower 12-bit cleared. |
| */ |
| protected void add(int size, Register dst, Register src, int aimm) { |
| assert !dst.equals(zr); |
| assert !src.equals(zr); |
| addSubImmInstruction(ADD, dst, src, aimm, generalFromSize(size)); |
| } |
| |
| /** |
| * dst = src + aimm and sets condition flags. |
| * |
| * @param size register size. Has to be 32 or 64. |
| * @param dst general purpose register. May not be null or stackpointer. |
| * @param src general purpose register. May not be null or zero-register. |
| * @param aimm arithmetic immediate. Either unsigned 12-bit value or unsigned 24-bit value with |
| * the lower 12-bit cleared. |
| */ |
| protected void adds(int size, Register dst, Register src, int aimm) { |
| assert !dst.equals(sp); |
| assert !src.equals(zr); |
| addSubImmInstruction(ADDS, dst, src, aimm, generalFromSize(size)); |
| } |
| |
| /** |
| * dst = src - aimm. |
| * |
| * @param size register size. Has to be 32 or 64. |
| * @param dst general purpose register. May not be null or zero-register. |
| * @param src general purpose register. May not be null or zero-register. |
| * @param aimm arithmetic immediate. Either unsigned 12-bit value or unsigned 24-bit value with |
| * the lower 12-bit cleared. |
| */ |
| protected void sub(int size, Register dst, Register src, int aimm) { |
| assert !dst.equals(zr); |
| assert !src.equals(zr); |
| addSubImmInstruction(SUB, dst, src, aimm, generalFromSize(size)); |
| } |
| |
| /** |
| * dst = src - aimm and sets condition flags. |
| * |
| * @param size register size. Has to be 32 or 64. |
| * @param dst general purpose register. May not be null or stackpointer. |
| * @param src general purpose register. May not be null or zero-register. |
| * @param aimm arithmetic immediate. Either unsigned 12-bit value or unsigned 24-bit value with |
| * the lower 12-bit cleared. |
| */ |
| protected void subs(int size, Register dst, Register src, int aimm) { |
| assert !dst.equals(sp); |
| assert !src.equals(zr); |
| addSubImmInstruction(SUBS, dst, src, aimm, generalFromSize(size)); |
| } |
| |
| private void addSubImmInstruction(Instruction instr, Register dst, Register src, int aimm, InstructionType type) { |
| emitInt(type.encoding | instr.encoding | AddSubImmOp | encodeAimm(aimm) | rd(dst) | rs1(src)); |
| } |
| |
| /** |
| * Encodes arithmetic immediate. |
| * |
| * @param imm Immediate has to be either an unsigned 12-bit value or an unsigned 24-bit value |
| * with the lower 12 bits zero. |
| * @return Representation of immediate for use with arithmetic instructions. |
| */ |
| private static int encodeAimm(int imm) { |
| assert isAimm(imm) : "Immediate has to be legal arithmetic immediate value " + imm; |
| if (NumUtil.isUnsignedNbit(12, imm)) { |
| return imm << ImmediateOffset; |
| } else { |
| // First 12-bit are zero, so shift immediate 12-bit and set flag to indicate |
| // shifted immediate value. |
| return (imm >>> 12 << ImmediateOffset) | AddSubShift12; |
| } |
| } |
| |
| /** |
| * Checks whether immediate can be encoded as an arithmetic immediate. |
| * |
| * @param imm Immediate has to be either an unsigned 12bit value or un unsigned 24bit value with |
| * the lower 12 bits 0. |
| * @return true if valid arithmetic immediate, false otherwise. |
| */ |
| protected static boolean isAimm(int imm) { |
| return NumUtil.isUnsignedNbit(12, imm) || NumUtil.isUnsignedNbit(12, imm >>> 12) && (imm & 0xfff) == 0; |
| } |
| |
| /* Logical (immediate) (5.4.2) */ |
| |
| /** |
| * dst = src & bimm. |
| * |
| * @param size register size. Has to be 32 or 64. |
| * @param dst general purpose register. May not be null or zero-register. |
| * @param src general purpose register. May not be null or stack-pointer. |
| * @param bimm logical immediate. See {@link LogicalImmediateTable} for exact definition. |
| */ |
| public void and(int size, Register dst, Register src, long bimm) { |
| assert !dst.equals(zr); |
| assert !src.equals(sp); |
| logicalImmInstruction(AND, dst, src, bimm, generalFromSize(size)); |
| } |
| |
| /** |
| * dst = src & bimm and sets condition flags. |
| * |
| * @param size register size. Has to be 32 or 64. |
| * @param dst general purpose register. May not be null or stack-pointer. |
| * @param src general purpose register. May not be null or stack-pointer. |
| * @param bimm logical immediate. See {@link LogicalImmediateTable} for exact definition. |
| */ |
| public void ands(int size, Register dst, Register src, long bimm) { |
| assert !dst.equals(sp); |
| assert !src.equals(sp); |
| logicalImmInstruction(ANDS, dst, src, bimm, generalFromSize(size)); |
| } |
| |
| /** |
| * dst = src ^ bimm. |
| * |
| * @param size register size. Has to be 32 or 64. |
| * @param dst general purpose register. May not be null or zero-register. |
| * @param src general purpose register. May not be null or stack-pointer. |
| * @param bimm logical immediate. See {@link LogicalImmediateTable} for exact definition. |
| */ |
| public void eor(int size, Register dst, Register src, long bimm) { |
| assert !dst.equals(zr); |
| assert !src.equals(sp); |
| logicalImmInstruction(EOR, dst, src, bimm, generalFromSize(size)); |
| } |
| |
| /** |
| * dst = src | bimm. |
| * |
| * @param size register size. Has to be 32 or 64. |
| * @param dst general purpose register. May not be null or zero-register. |
| * @param src general purpose register. May not be null or stack-pointer. |
| * @param bimm logical immediate. See {@link LogicalImmediateTable} for exact definition. |
| */ |
| protected void orr(int size, Register dst, Register src, long bimm) { |
| assert !dst.equals(zr); |
| assert !src.equals(sp); |
| logicalImmInstruction(ORR, dst, src, bimm, generalFromSize(size)); |
| } |
| |
| private void logicalImmInstruction(Instruction instr, Register dst, Register src, long bimm, InstructionType type) { |
| // Mask higher bits off, since we always pass longs around even for the 32-bit instruction. |
| long bimmValue; |
| if (type == General32) { |
| assert (bimm >> 32) == 0 || (bimm >> 32) == -1L : "Higher order bits for 32-bit instruction must either all be 0 or 1."; |
| bimmValue = bimm & NumUtil.getNbitNumberLong(32); |
| } else { |
| bimmValue = bimm; |
| } |
| int immEncoding = LogicalImmediateTable.getLogicalImmEncoding(type == General64, bimmValue); |
| emitInt(type.encoding | instr.encoding | LogicalImmOp | immEncoding | rd(dst) | rs1(src)); |
| } |
| |
| /* Move (wide immediate) (5.4.3) */ |
| |
| /** |
| * dst = uimm16 << shiftAmt. |
| * |
| * @param size register size. Has to be 32 or 64. |
| * @param dst general purpose register. May not be null, stackpointer or zero-register. |
| * @param uimm16 16-bit unsigned immediate |
| * @param shiftAmt amount by which uimm16 is left shifted. Can be any multiple of 16 smaller |
| * than size. |
| */ |
| protected void movz(int size, Register dst, int uimm16, int shiftAmt) { |
| moveWideImmInstruction(MOVZ, dst, uimm16, shiftAmt, generalFromSize(size)); |
| } |
| |
| /** |
| * dst = ~(uimm16 << shiftAmt). |
| * |
| * @param size register size. Has to be 32 or 64. |
| * @param dst general purpose register. May not be null, stackpointer or zero-register. |
| * @param uimm16 16-bit unsigned immediate |
| * @param shiftAmt amount by which uimm16 is left shifted. Can be any multiple of 16 smaller |
| * than size. |
| */ |
| protected void movn(int size, Register dst, int uimm16, int shiftAmt) { |
| moveWideImmInstruction(MOVN, dst, uimm16, shiftAmt, generalFromSize(size)); |
| } |
| |
| /** |
| * dst<pos+15:pos> = uimm16. |
| * |
| * @param size register size. Has to be 32 or 64. |
| * @param dst general purpose register. May not be null, stackpointer or zero-register. |
| * @param uimm16 16-bit unsigned immediate |
| * @param pos position into which uimm16 is inserted. Can be any multiple of 16 smaller than |
| * size. |
| */ |
| protected void movk(int size, Register dst, int uimm16, int pos) { |
| moveWideImmInstruction(MOVK, dst, uimm16, pos, generalFromSize(size)); |
| } |
| |
| private void moveWideImmInstruction(Instruction instr, Register dst, int uimm16, int shiftAmt, InstructionType type) { |
| assert dst.getRegisterCategory().equals(CPU); |
| assert NumUtil.isUnsignedNbit(16, uimm16) : "Immediate has to be unsigned 16bit"; |
| assert shiftAmt == 0 || shiftAmt == 16 || (type == InstructionType.General64 && (shiftAmt == 32 || shiftAmt == 48)) : "Invalid shift amount: " + shiftAmt; |
| int shiftValue = shiftAmt >> 4; |
| emitInt(type.encoding | instr.encoding | MoveWideImmOp | rd(dst) | uimm16 << MoveWideImmOffset | shiftValue << MoveWideShiftOffset); |
| } |
| |
| /* Bitfield Operations (5.4.5) */ |
| |
| /** |
| * Bitfield move. |
| * |
| * @param size register size. Has to be 32 or 64. |
| * @param dst general purpose register. May not be null, stackpointer or zero-register. |
| * @param src general purpose register. May not be null, stackpointer or zero-register. |
| * @param r must be in the range 0 to size - 1 |
| * @param s must be in the range 0 to size - 1 |
| */ |
| protected void bfm(int size, Register dst, Register src, int r, int s) { |
| bitfieldInstruction(BFM, dst, src, r, s, generalFromSize(size)); |
| } |
| |
| /** |
| * Unsigned bitfield move. |
| * |
| * @param size register size. Has to be 32 or 64. |
| * @param dst general purpose register. May not be null, stackpointer or zero-register. |
| * @param src general purpose register. May not be null, stackpointer or zero-register. |
| * @param r must be in the range 0 to size - 1 |
| * @param s must be in the range 0 to size - 1 |
| */ |
| protected void ubfm(int size, Register dst, Register src, int r, int s) { |
| bitfieldInstruction(UBFM, dst, src, r, s, generalFromSize(size)); |
| } |
| |
| /** |
| * Signed bitfield move. |
| * |
| * @param size register size. Has to be 32 or 64. |
| * @param dst general purpose register. May not be null, stackpointer or zero-register. |
| * @param src general purpose register. May not be null, stackpointer or zero-register. |
| * @param r must be in the range 0 to size - 1 |
| * @param s must be in the range 0 to size - 1 |
| */ |
| protected void sbfm(int size, Register dst, Register src, int r, int s) { |
| bitfieldInstruction(SBFM, dst, src, r, s, generalFromSize(size)); |
| } |
| |
| private void bitfieldInstruction(Instruction instr, Register dst, Register src, int r, int s, InstructionType type) { |
| assert !dst.equals(sp) && !dst.equals(zr); |
| assert !src.equals(sp) && !src.equals(zr); |
| assert s >= 0 && s < type.width && r >= 0 && r < type.width; |
| int sf = type == General64 ? 1 << ImmediateSizeOffset : 0; |
| emitInt(type.encoding | instr.encoding | BitfieldImmOp | sf | r << ImmediateRotateOffset | s << ImmediateOffset | rd(dst) | rs1(src)); |
| } |
| |
| /* Extract (Immediate) (5.4.6) */ |
| |
| /** |
| * Extract. dst = src1:src2<lsb+31:lsb> |
| * |
| * @param size register size. Has to be 32 or 64. |
| * @param dst general purpose register. May not be null or stackpointer. |
| * @param src1 general purpose register. May not be null or stackpointer. |
| * @param src2 general purpose register. May not be null or stackpointer. |
| * @param lsb must be in range 0 to size - 1. |
| */ |
| protected void extr(int size, Register dst, Register src1, Register src2, int lsb) { |
| assert !dst.equals(sp); |
| assert !src1.equals(sp); |
| assert !src2.equals(sp); |
| InstructionType type = generalFromSize(size); |
| assert lsb >= 0 && lsb < type.width; |
| int sf = type == General64 ? 1 << ImmediateSizeOffset : 0; |
| emitInt(type.encoding | EXTR.encoding | sf | lsb << ImmediateOffset | rd(dst) | rs1(src1) | rs2(src2)); |
| } |
| |
| /* Arithmetic (shifted register) (5.5.1) */ |
| |
| /** |
| * dst = src1 + shiftType(src2, imm). |
| * |
| * @param size register size. Has to be 32 or 64. |
| * @param dst general purpose register. May not be null or stackpointer. |
| * @param src1 general purpose register. May not be null or stackpointer. |
| * @param src2 general purpose register. May not be null or stackpointer. |
| * @param shiftType any type but ROR. |
| * @param imm must be in range 0 to size - 1. |
| */ |
| protected void add(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) { |
| addSubShiftedInstruction(ADD, dst, src1, src2, shiftType, imm, generalFromSize(size)); |
| } |
| |
| /** |
| * dst = src1 + shiftType(src2, imm) and sets condition flags. |
| * |
| * @param size register size. Has to be 32 or 64. |
| * @param dst general purpose register. May not be null or stackpointer. |
| * @param src1 general purpose register. May not be null or stackpointer. |
| * @param src2 general purpose register. May not be null or stackpointer. |
| * @param shiftType any type but ROR. |
| * @param imm must be in range 0 to size - 1. |
| */ |
| protected void adds(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) { |
| addSubShiftedInstruction(ADDS, dst, src1, src2, shiftType, imm, generalFromSize(size)); |
| } |
| |
| /** |
| * dst = src1 - shiftType(src2, imm). |
| * |
| * @param size register size. Has to be 32 or 64. |
| * @param dst general purpose register. May not be null or stackpointer. |
| * @param src1 general purpose register. May not be null or stackpointer. |
| * @param src2 general purpose register. May not be null or stackpointer. |
| * @param shiftType any type but ROR. |
| * @param imm must be in range 0 to size - 1. |
| */ |
| protected void sub(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) { |
| addSubShiftedInstruction(SUB, dst, src1, src2, shiftType, imm, generalFromSize(size)); |
| } |
| |
| /** |
| * dst = src1 - shiftType(src2, imm) and sets condition flags. |
| * |
| * @param size register size. Has to be 32 or 64. |
| * @param dst general purpose register. May not be null or stackpointer. |
| * @param src1 general purpose register. May not be null or stackpointer. |
| * @param src2 general purpose register. May not be null or stackpointer. |
| * @param shiftType any type but ROR. |
| * @param imm must be in range 0 to size - 1. |
| */ |
| protected void subs(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) { |
| addSubShiftedInstruction(SUBS, dst, src1, src2, shiftType, imm, generalFromSize(size)); |
| } |
| |
| private void addSubShiftedInstruction(Instruction instr, Register dst, Register src1, Register src2, ShiftType shiftType, int imm, InstructionType type) { |
| assert shiftType != ShiftType.ROR; |
| assert imm >= 0 && imm < type.width; |
| emitInt(type.encoding | instr.encoding | AddSubShiftedOp | imm << ImmediateOffset | shiftType.encoding << ShiftTypeOffset | rd(dst) | rs1(src1) | rs2(src2)); |
| } |
| |
| /* Arithmetic (extended register) (5.5.2) */ |
| /** |
| * dst = src1 + extendType(src2) << imm. |
| * |
| * @param size register size. Has to be 32 or 64. |
| * @param dst general purpose register. May not be null or zero-register.. |
| * @param src1 general purpose register. May not be null or zero-register. |
| * @param src2 general purpose register. May not be null or stackpointer. |
| * @param extendType defines how src2 is extended to the same size as src1. |
| * @param shiftAmt must be in range 0 to 4. |
| */ |
| public void add(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) { |
| assert !dst.equals(zr); |
| assert !src1.equals(zr); |
| assert !src2.equals(sp); |
| addSubExtendedInstruction(ADD, dst, src1, src2, extendType, shiftAmt, generalFromSize(size)); |
| } |
| |
| /** |
| * dst = src1 + extendType(src2) << imm and sets condition flags. |
| * |
| * @param size register size. Has to be 32 or 64. |
| * @param dst general purpose register. May not be null or stackpointer.. |
| * @param src1 general purpose register. May not be null or zero-register. |
| * @param src2 general purpose register. May not be null or stackpointer. |
| * @param extendType defines how src2 is extended to the same size as src1. |
| * @param shiftAmt must be in range 0 to 4. |
| */ |
| protected void adds(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) { |
| assert !dst.equals(sp); |
| assert !src1.equals(zr); |
| assert !src2.equals(sp); |
| addSubExtendedInstruction(ADDS, dst, src1, src2, extendType, shiftAmt, generalFromSize(size)); |
| } |
| |
| /** |
| * dst = src1 - extendType(src2) << imm. |
| * |
| * @param size register size. Has to be 32 or 64. |
| * @param dst general purpose register. May not be null or zero-register.. |
| * @param src1 general purpose register. May not be null or zero-register. |
| * @param src2 general purpose register. May not be null or stackpointer. |
| * @param extendType defines how src2 is extended to the same size as src1. |
| * @param shiftAmt must be in range 0 to 4. |
| */ |
| protected void sub(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) { |
| assert !dst.equals(zr); |
| assert !src1.equals(zr); |
| assert !src2.equals(sp); |
| addSubExtendedInstruction(SUB, dst, src1, src2, extendType, shiftAmt, generalFromSize(size)); |
| } |
| |
| /** |
| * dst = src1 - extendType(src2) << imm and sets flags. |
| * |
| * @param size register size. Has to be 32 or 64. |
| * @param dst general purpose register. May not be null or stackpointer.. |
| * @param src1 general purpose register. May not be null or zero-register. |
| * @param src2 general purpose register. May not be null or stackpointer. |
| * @param extendType defines how src2 is extended to the same size as src1. |
| * @param shiftAmt must be in range 0 to 4. |
| */ |
| protected void subs(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) { |
| assert !dst.equals(sp); |
| assert !src1.equals(zr); |
| assert !src2.equals(sp); |
| addSubExtendedInstruction(SUBS, dst, src1, src2, extendType, shiftAmt, generalFromSize(size)); |
| } |
| |
| private void addSubExtendedInstruction(Instruction instr, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt, InstructionType type) { |
| assert shiftAmt >= 0 && shiftAmt <= 4; |
| emitInt(type.encoding | instr.encoding | AddSubExtendedOp | shiftAmt << ImmediateOffset | extendType.encoding << ExtendTypeOffset | rd(dst) | rs1(src1) | rs2(src2)); |
| } |
| |
| /* Logical (shifted register) (5.5.3) */ |
| /** |
| * dst = src1 & shiftType(src2, imm). |
| * |
| * @param size register size. Has to be 32 or 64. |
| * @param dst general purpose register. May not be null or stackpointer. |
| * @param src1 general purpose register. May not be null or stackpointer. |
| * @param src2 general purpose register. May not be null or stackpointer. |
| * @param shiftType all types allowed, may not be null. |
| * @param shiftAmt must be in range 0 to size - 1. |
| */ |
| protected void and(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) { |
| logicalRegInstruction(AND, dst, src1, src2, shiftType, shiftAmt, generalFromSize(size)); |
| } |
| |
| /** |
| * dst = src1 & shiftType(src2, imm) and sets condition flags. |
| * |
| * @param size register size. Has to be 32 or 64. |
| * @param dst general purpose register. May not be null or stackpointer. |
| * @param src1 general purpose register. May not be null or stackpointer. |
| * @param src2 general purpose register. May not be null or stackpointer. |
| * @param shiftType all types allowed, may not be null. |
| * @param shiftAmt must be in range 0 to size - 1. |
| */ |
| protected void ands(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) { |
| logicalRegInstruction(ANDS, dst, src1, src2, shiftType, shiftAmt, generalFromSize(size)); |
| } |
| |
| /** |
| * dst = src1 & ~(shiftType(src2, imm)). |
| * |
| * @param size register size. Has to be 32 or 64. |
| * @param dst general purpose register. May not be null or stackpointer. |
| * @param src1 general purpose register. May not be null or stackpointer. |
| * @param src2 general purpose register. May not be null or stackpointer. |
| * @param shiftType all types allowed, may not be null. |
| * @param shiftAmt must be in range 0 to size - 1. |
| */ |
| protected void bic(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) { |
| logicalRegInstruction(BIC, dst, src1, src2, shiftType, shiftAmt, generalFromSize(size)); |
| } |
| |
| /** |
| * dst = src1 & ~(shiftType(src2, imm)) and sets condition flags. |
| * |
| * @param size register size. Has to be 32 or 64. |
| * @param dst general purpose register. May not be null or stackpointer. |
| * @param src1 general purpose register. May not be null or stackpointer. |
| * @param src2 general purpose register. May not be null or stackpointer. |
| * @param shiftType all types allowed, may not be null. |
| * @param shiftAmt must be in range 0 to size - 1. |
| */ |
| protected void bics(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) { |
| logicalRegInstruction(BICS, dst, src1, src2, shiftType, shiftAmt, generalFromSize(size)); |
| } |
| |
| /** |
| * dst = src1 ^ ~(shiftType(src2, imm)). |
| * |
| * @param size register size. Has to be 32 or 64. |
| * @param dst general purpose register. May not be null or stackpointer. |
| * @param src1 general purpose register. May not be null or stackpointer. |
| * @param src2 general purpose register. May not be null or stackpointer. |
| * @param shiftType all types allowed, may not be null. |
| * @param shiftAmt must be in range 0 to size - 1. |
| */ |
| protected void eon(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) { |
| logicalRegInstruction(EON, dst, src1, src2, shiftType, shiftAmt, generalFromSize(size)); |
| } |
| |
| /** |
| * dst = src1 ^ shiftType(src2, imm). |
| * |
| * @param size register size. Has to be 32 or 64. |
| * @param dst general purpose register. May not be null or stackpointer. |
| * @param src1 general purpose register. May not be null or stackpointer. |
| * @param src2 general purpose register. May not be null or stackpointer. |
| * @param shiftType all types allowed, may not be null. |
| * @param shiftAmt must be in range 0 to size - 1. |
| */ |
| protected void eor(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) { |
| logicalRegInstruction(EOR, dst, src1, src2, shiftType, shiftAmt, generalFromSize(size)); |
| } |
| |
| /** |
| * dst = src1 | shiftType(src2, imm). |
| * |
| * @param size register size. Has to be 32 or 64. |
| * @param dst general purpose register. May not be null or stackpointer. |
| * @param src1 general purpose register. May not be null or stackpointer. |
| * @param src2 general purpose register. May not be null or stackpointer. |
| * @param shiftType all types allowed, may not be null. |
| * @param shiftAmt must be in range 0 to size - 1. |
| */ |
| protected void orr(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) { |
| logicalRegInstruction(ORR, dst, src1, src2, shiftType, shiftAmt, generalFromSize(size)); |
| } |
| |
| /** |
| * dst = src1 | ~(shiftType(src2, imm)). |
| * |
| * @param size register size. Has to be 32 or 64. |
| * @param dst general purpose register. May not be null or stackpointer. |
| * @param src1 general purpose register. May not be null or stackpointer. |
| * @param src2 general purpose register. May not be null or stackpointer. |
| * @param shiftType all types allowed, may not be null. |
| * @param shiftAmt must be in range 0 to size - 1. |
| */ |
| protected void orn(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) { |
| logicalRegInstruction(ORN, dst, src1, src2, shiftType, shiftAmt, generalFromSize(size)); |
| } |
| |
| private void logicalRegInstruction(Instruction instr, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt, InstructionType type) { |
| assert !dst.equals(sp); |
| assert !src1.equals(sp); |
| assert !src2.equals(sp); |
| assert shiftAmt >= 0 && shiftAmt < type.width; |
| emitInt(type.encoding | instr.encoding | LogicalShiftOp | shiftAmt << ImmediateOffset | shiftType.encoding << ShiftTypeOffset | rd(dst) | rs1(src1) | rs2(src2)); |
| } |
| |
| /* Variable Shift (5.5.4) */ |
| /** |
| * dst = src1 >> (src2 & log2(size)). |
| * |
| * @param size register size. Has to be 32 or 64. |
| * @param dst general purpose register. May not be null or stackpointer. |
| * @param src1 general purpose register. May not be null or stackpointer. |
| * @param src2 general purpose register. May not be null or stackpointer. |
| */ |
| protected void asr(int size, Register dst, Register src1, Register src2) { |
| dataProcessing2SourceOp(ASRV, dst, src1, src2, generalFromSize(size)); |
| } |
| |
| /** |
| * dst = src1 << (src2 & log2(size)). |
| * |
| * @param size register size. Has to be 32 or 64. |
| * @param dst general purpose register. May not be null or stackpointer. |
| * @param src1 general purpose register. May not be null or stackpointer. |
| * @param src2 general purpose register. May not be null or stackpointer. |
| */ |
| protected void lsl(int size, Register dst, Register src1, Register src2) { |
| dataProcessing2SourceOp(LSLV, dst, src1, src2, generalFromSize(size)); |
| } |
| |
| /** |
| * dst = src1 >>> (src2 & log2(size)). |
| * |
| * @param size register size. Has to be 32 or 64. |
| * @param dst general purpose register. May not be null or stackpointer. |
| * @param src1 general purpose register. May not be null or stackpointer. |
| * @param src2 general purpose register. May not be null or stackpointer. |
| */ |
| protected void lsr(int size, Register dst, Register src1, Register src2) { |
| dataProcessing2SourceOp(LSRV, dst, src1, src2, generalFromSize(size)); |
| } |
| |
| /** |
| * dst = rotateRight(src1, (src2 & log2(size))). |
| * |
| * @param size register size. Has to be 32 or 64. |
| * @param dst general purpose register. May not be null or stackpointer. |
| * @param src1 general purpose register. May not be null or stackpointer. |
| * @param src2 general purpose register. May not be null or stackpointer. |
| */ |
| protected void ror(int size, Register dst, Register src1, Register src2) { |
| dataProcessing2SourceOp(RORV, dst, src1, src2, generalFromSize(size)); |
| } |
| |
| /* Bit Operations (5.5.5) */ |
| |
| /** |
| * Counts leading sign bits. Sets Wd to the number of consecutive bits following the topmost bit |
| * in dst, that are the same as the topmost bit. The count does not include the topmost bit |
| * itself , so the result will be in the range 0 to size-1 inclusive. |
| * |
| * @param size register size. Has to be 32 or 64. |
| * @param dst general purpose register. May not be null, zero-register or the stackpointer. |
| * @param src source register. May not be null, zero-register or the stackpointer. |
| */ |
| protected void cls(int size, Register dst, Register src) { |
| dataProcessing1SourceOp(CLS, dst, src, generalFromSize(size)); |
| } |
| |
| /** |
| * Counts leading zeros. |
| * |
| * @param size register size. Has to be 32 or 64. |
| * @param dst general purpose register. May not be null, zero-register or the stackpointer. |
| * @param src source register. May not be null, zero-register or the stackpointer. |
| */ |
| public void clz(int size, Register dst, Register src) { |
| dataProcessing1SourceOp(CLZ, dst, src, generalFromSize(size)); |
| } |
| |
| /** |
| * Reverses bits. |
| * |
| * @param size register size. Has to be 32 or 64. |
| * @param dst general purpose register. May not be null, zero-register or the stackpointer. |
| * @param src source register. May not be null, zero-register or the stackpointer. |
| */ |
| protected void rbit(int size, Register dst, Register src) { |
| dataProcessing1SourceOp(RBIT, dst, src, generalFromSize(size)); |
| } |
| |
| /** |
| * Reverses bytes. |
| * |
| * @param size register size. Has to be 32 or 64. |
| * @param dst general purpose register. May not be null or the stackpointer. |
| * @param src source register. May not be null or the stackpointer. |
| */ |
| public void rev(int size, Register dst, Register src) { |
| if (size == 64) { |
| dataProcessing1SourceOp(REVX, dst, src, generalFromSize(size)); |
| } else { |
| assert size == 32; |
| dataProcessing1SourceOp(REVW, dst, src, generalFromSize(size)); |
| } |
| } |
| |
| /* Conditional Data Processing (5.5.6) */ |
| |
| /** |
| * Conditional select. dst = src1 if condition else src2. |
| * |
| * @param size register size. Has to be 32 or 64. |
| * @param dst general purpose register. May not be null or the stackpointer. |
| * @param src1 general purpose register. May not be null or the stackpointer. |
| * @param src2 general purpose register. May not be null or the stackpointer. |
| * @param condition any condition flag. May not be null. |
| */ |
| protected void csel(int size, Register dst, Register src1, Register src2, ConditionFlag condition) { |
| conditionalSelectInstruction(CSEL, dst, src1, src2, condition, generalFromSize(size)); |
| } |
| |
| /** |
| * Conditional select negate. dst = src1 if condition else -src2. |
| * |
| * @param size register size. Has to be 32 or 64. |
| * @param dst general purpose register. May not be null or the stackpointer. |
| * @param src1 general purpose register. May not be null or the stackpointer. |
| * @param src2 general purpose register. May not be null or the stackpointer. |
| * @param condition any condition flag. May not be null. |
| */ |
| protected void csneg(int size, Register dst, Register src1, Register src2, ConditionFlag condition) { |
| conditionalSelectInstruction(CSNEG, dst, src1, src2, condition, generalFromSize(size)); |
| } |
| |
| /** |
| * Conditional increase. dst = src1 if condition else src2 + 1. |
| * |
| * @param size register size. Has to be 32 or 64. |
| * @param dst general purpose register. May not be null or the stackpointer. |
| * @param src1 general purpose register. May not be null or the stackpointer. |
| * @param src2 general purpose register. May not be null or the stackpointer. |
| * @param condition any condition flag. May not be null. |
| */ |
| protected void csinc(int size, Register dst, Register src1, Register src2, ConditionFlag condition) { |
| conditionalSelectInstruction(CSINC, dst, src1, src2, condition, generalFromSize(size)); |
| } |
| |
| private void conditionalSelectInstruction(Instruction instr, Register dst, Register src1, Register src2, ConditionFlag condition, InstructionType type) { |
| assert !dst.equals(sp); |
| assert !src1.equals(sp); |
| assert !src2.equals(sp); |
| emitInt(type.encoding | instr.encoding | ConditionalSelectOp | rd(dst) | rs1(src1) | rs2(src2) | condition.encoding << ConditionalConditionOffset); |
| } |
| |
| /* Integer Multiply/Divide (5.6) */ |
| |
| /** |
| * dst = src1 * src2 + src3. |
| * |
| * @param size register size. Has to be 32 or 64. |
| * @param dst general purpose register. May not be null or the stackpointer. |
| * @param src1 general purpose register. May not be null or the stackpointer. |
| * @param src2 general purpose register. May not be null or the stackpointer. |
| * @param src3 general purpose register. May not be null or the stackpointer. |
| */ |
| protected void madd(int size, Register dst, Register src1, Register src2, Register src3) { |
| mulInstruction(MADD, dst, src1, src2, src3, generalFromSize(size)); |
| } |
| |
| /** |
| * dst = src3 - src1 * src2. |
| * |
| * @param size register size. Has to be 32 or 64. |
| * @param dst general purpose register. May not be null or the stackpointer. |
| * @param src1 general purpose register. May not be null or the stackpointer. |
| * @param src2 general purpose register. May not be null or the stackpointer. |
| * @param src3 general purpose register. May not be null or the stackpointer. |
| */ |
| protected void msub(int size, Register dst, Register src1, Register src2, Register src3) { |
| mulInstruction(MSUB, dst, src1, src2, src3, generalFromSize(size)); |
| } |
| |
| /** |
| * Signed multiply high. dst = (src1 * src2)[127:64] |
| * |
| * @param dst general purpose register. May not be null or the stackpointer. |
| * @param src1 general purpose register. May not be null or the stackpointer. |
| * @param src2 general purpose register. May not be null or the stackpointer. |
| */ |
| protected void smulh(Register dst, Register src1, Register src2) { |
| assert !dst.equals(sp); |
| assert !src1.equals(sp); |
| assert !src2.equals(sp); |
| emitInt(0b10011011010 << 21 | dst.encoding | rs1(src1) | rs2(src2) | 0b011111 << ImmediateOffset); |
| } |
| |
| /** |
| * unsigned multiply high. dst = (src1 * src2)[127:64] |
| * |
| * @param dst general purpose register. May not be null or the stackpointer. |
| * @param src1 general purpose register. May not be null or the stackpointer. |
| * @param src2 general purpose register. May not be null or the stackpointer. |
| */ |
| protected void umulh(Register dst, Register src1, Register src2) { |
| assert !dst.equals(sp); |
| assert !src1.equals(sp); |
| assert !src2.equals(sp); |
| emitInt(0b10011011110 << 21 | dst.encoding | rs1(src1) | rs2(src2) | 0b011111 << ImmediateOffset); |
| } |
| |
| /** |
| * unsigned multiply add-long. xDst = xSrc3 + (wSrc1 * wSrc2) |
| * |
| * @param dst general purpose register. May not be null or the stackpointer. |
| * @param src1 general purpose register. May not be null or the stackpointer. |
| * @param src2 general purpose register. May not be null or the stackpointer. |
| * @param src3 general purpose register. May not be null or the stackpointer. |
| */ |
| protected void umaddl(Register dst, Register src1, Register src2, Register src3) { |
| assert !dst.equals(sp); |
| assert !src1.equals(sp); |
| assert !src2.equals(sp); |
| assert !src3.equals(sp); |
| emitInt(0b10011011101 << 21 | dst.encoding | rs1(src1) | rs2(src2) | 0b011111 << ImmediateOffset); |
| } |
| |
| /** |
| * signed multiply add-long. xDst = xSrc3 + (wSrc1 * wSrc2) |
| * |
| * @param dst general purpose register. May not be null or the stackpointer. |
| * @param src1 general purpose register. May not be null or the stackpointer. |
| * @param src2 general purpose register. May not be null or the stackpointer. |
| * @param src3 general purpose register. May not be null or the stackpointer. |
| */ |
| protected void smaddl(Register dst, Register src1, Register src2, Register src3) { |
| assert !dst.equals(sp); |
| assert !src1.equals(sp); |
| assert !src2.equals(sp); |
| assert !src3.equals(sp); |
| emitInt(0b10011011001 << 21 | dst.encoding | rs1(src1) | rs2(src2) | rs3(src3)); |
| } |
| |
| private void mulInstruction(Instruction instr, Register dst, Register src1, Register src2, Register src3, InstructionType type) { |
| assert !dst.equals(sp); |
| assert !src1.equals(sp); |
| assert !src2.equals(sp); |
| assert !src3.equals(sp); |
| emitInt(type.encoding | instr.encoding | MulOp | rd(dst) | rs1(src1) | rs2(src2) | rs3(src3)); |
| } |
| |
| /** |
| * Signed divide. dst = src1 / src2. |
| * |
| * @param size register size. Has to be 32 or 64. |
| * @param dst general purpose register. May not be null or the stackpointer. |
| * @param src1 general purpose register. May not be null or the stackpointer. |
| * @param src2 general purpose register. May not be null or the stackpointer. |
| */ |
| public void sdiv(int size, Register dst, Register src1, Register src2) { |
| dataProcessing2SourceOp(SDIV, dst, src1, src2, generalFromSize(size)); |
| } |
| |
| /** |
| * Unsigned divide. dst = src1 / src2. |
| * |
| * @param size register size. Has to be 32 or 64. |
| * @param dst general purpose register. May not be null or the stackpointer. |
| * @param src1 general purpose register. May not be null or the stackpointer. |
| * @param src2 general purpose register. May not be null or the stackpointer. |
| */ |
| public void udiv(int size, Register dst, Register src1, Register src2) { |
| dataProcessing2SourceOp(UDIV, dst, src1, src2, generalFromSize(size)); |
| } |
| |
| private void dataProcessing1SourceOp(Instruction instr, Register dst, Register src, InstructionType type) { |
| emitInt(type.encoding | instr.encoding | DataProcessing1SourceOp | rd(dst) | rs1(src)); |
| } |
| |
| private void dataProcessing2SourceOp(Instruction instr, Register dst, Register src1, Register src2, InstructionType type) { |
| assert !dst.equals(sp); |
| assert !src1.equals(sp); |
| assert !src2.equals(sp); |
| emitInt(type.encoding | instr.encoding | DataProcessing2SourceOp | rd(dst) | rs1(src1) | rs2(src2)); |
| } |
| |
| /* Floating point operations */ |
| |
| /* Load-Store Single FP register (5.7.1.1) */ |
| /** |
| * Floating point load. |
| * |
| * @param size number of bits read from memory into rt. Must be 32 or 64. |
| * @param rt floating point register. May not be null. |
| * @param address all addressing modes allowed. May not be null. |
| */ |
| public void fldr(int size, Register rt, AArch64Address address) { |
| assert rt.getRegisterCategory().equals(SIMD); |
| assert size == 32 || size == 64; |
| int transferSize = NumUtil.log2Ceil(size / 8); |
| loadStoreInstruction(LDR, rt, address, InstructionType.FP32, transferSize); |
| } |
| |
| /** |
| * Floating point store. |
| * |
| * @param size number of bits read from memory into rt. Must be 32 or 64. |
| * @param rt floating point register. May not be null. |
| * @param address all addressing modes allowed. May not be null. |
| */ |
| public void fstr(int size, Register rt, AArch64Address address) { |
| assert rt.getRegisterCategory().equals(SIMD); |
| assert size == 32 || size == 64; |
| int transferSize = NumUtil.log2Ceil(size / 8); |
| loadStoreInstruction(STR, rt, address, InstructionType.FP64, transferSize); |
| } |
| |
| /* Floating-point Move (register) (5.7.2) */ |
| |
| /** |
| * Floating point move. |
| * |
| * @param size register size. Has to be 32 or 64. |
| * @param dst floating point register. May not be null. |
| * @param src floating point register. May not be null. |
| */ |
| protected void fmov(int size, Register dst, Register src) { |
| fpDataProcessing1Source(FMOV, dst, src, floatFromSize(size)); |
| } |
| |
| /** |
| * Move size bits from floating point register unchanged to general purpose register. |
| * |
| * @param size number of bits read from memory into rt. Must be 32 or 64. |
| * @param dst general purpose register. May not be null, stack-pointer or zero-register |
| * @param src floating point register. May not be null. |
| */ |
| protected void fmovFpu2Cpu(int size, Register dst, Register src) { |
| assert dst.getRegisterCategory().equals(CPU); |
| assert src.getRegisterCategory().equals(SIMD); |
| fmovCpuFpuInstruction(dst, src, size == 64, Instruction.FMOVFPU2CPU); |
| } |
| |
| /** |
| * Move size bits from general purpose register unchanged to floating point register. |
| * |
| * @param size register size. Has to be 32 or 64. |
| * @param dst floating point register. May not be null. |
| * @param src general purpose register. May not be null or stack-pointer. |
| */ |
| protected void fmovCpu2Fpu(int size, Register dst, Register src) { |
| assert dst.getRegisterCategory().equals(SIMD); |
| assert src.getRegisterCategory().equals(CPU); |
| fmovCpuFpuInstruction(dst, src, size == 64, Instruction.FMOVCPU2FPU); |
| } |
| |
| private void fmovCpuFpuInstruction(Register dst, Register src, boolean is64bit, Instruction instr) { |
| int sf = is64bit ? FP64.encoding | General64.encoding : FP32.encoding | General32.encoding; |
| emitInt(sf | instr.encoding | FpConvertOp | rd(dst) | rs1(src)); |
| } |
| |
| /* Floating-point Move (immediate) (5.7.3) */ |
| |
| /** |
| * Move immediate into register. |
| * |
| * @param size register size. Has to be 32 or 64. |
| * @param dst floating point register. May not be null. |
| * @param imm immediate that is loaded into dst. If size is 32 only float immediates can be |
| * loaded, i.e. (float) imm == imm must be true. In all cases |
| * {@code isFloatImmediate}, respectively {@code #isDoubleImmediate} must be true |
| * depending on size. |
| */ |
| protected void fmov(int size, Register dst, double imm) { |
| assert dst.getRegisterCategory().equals(SIMD); |
| InstructionType type = floatFromSize(size); |
| int immEncoding; |
| if (type == FP64) { |
| immEncoding = getDoubleImmediate(imm); |
| } else { |
| assert imm == (float) imm : "float mov must use an immediate that can be represented using a float."; |
| immEncoding = getFloatImmediate((float) imm); |
| } |
| emitInt(type.encoding | FMOV.encoding | FpImmOp | immEncoding | rd(dst)); |
| } |
| |
| private static int getDoubleImmediate(double imm) { |
| assert isDoubleImmediate(imm); |
| // bits: aBbb.bbbb.bbcd.efgh.0000.0000.0000.0000 |
| // 0000.0000.0000.0000.0000.0000.0000.0000 |
| long repr = Double.doubleToRawLongBits(imm); |
| int a = (int) (repr >>> 63) << 7; |
| int b = (int) ((repr >>> 61) & 0x1) << 6; |
| int cToH = (int) (repr >>> 48) & 0x3f; |
| return (a | b | cToH) << FpImmOffset; |
| } |
| |
| protected static boolean isDoubleImmediate(double imm) { |
| // Valid values will have the form: |
| // aBbb.bbbb.bbcd.efgh.0000.0000.0000.0000 |
| // 0000.0000.0000.0000.0000.0000.0000.0000 |
| long bits = Double.doubleToRawLongBits(imm); |
| // lower 48 bits are cleared |
| if ((bits & NumUtil.getNbitNumberLong(48)) != 0) { |
| return false; |
| } |
| // bits[61..54] are all set or all cleared. |
| long pattern = (bits >> 54) & NumUtil.getNbitNumberLong(7); |
| if (pattern != 0 && pattern != NumUtil.getNbitNumberLong(7)) { |
| return false; |
| } |
| // bits[62] and bits[61] are opposites. |
| return ((bits ^ (bits << 1)) & (1L << 62)) != 0; |
| } |
| |
| private static int getFloatImmediate(float imm) { |
| assert isFloatImmediate(imm); |
| // bits: aBbb.bbbc.defg.h000.0000.0000.0000.0000 |
| int repr = Float.floatToRawIntBits(imm); |
| int a = (repr >>> 31) << 7; |
| int b = ((repr >>> 29) & 0x1) << 6; |
| int cToH = (repr >>> 19) & NumUtil.getNbitNumberInt(6); |
| return (a | b | cToH) << FpImmOffset; |
| } |
| |
| protected static boolean isFloatImmediate(float imm) { |
| // Valid values will have the form: |
| // aBbb.bbbc.defg.h000.0000.0000.0000.0000 |
| int bits = Float.floatToRawIntBits(imm); |
| // lower 20 bits are cleared. |
| if ((bits & NumUtil.getNbitNumberInt(19)) != 0) { |
| return false; |
| } |
| // bits[29..25] are all set or all cleared |
| int pattern = (bits >> 25) & NumUtil.getNbitNumberInt(5); |
| if (pattern != 0 && pattern != NumUtil.getNbitNumberInt(5)) { |
| return false; |
| } |
| // bits[29] and bits[30] have to be opposite |
| return ((bits ^ (bits << 1)) & (1 << 30)) != 0; |
| } |
| |
| /* Convert Floating-point Precision (5.7.4.1) */ |
| /* Converts float to double and vice-versa */ |
| |
| /** |
| * Convert float to double and vice-versa. |
| * |
| * @param srcSize size of source register in bits. |
| * @param dst floating point register. May not be null. |
| * @param src floating point register. May not be null. |
| */ |
| public void fcvt(int srcSize, Register dst, Register src) { |
| if (srcSize == 32) { |
| fpDataProcessing1Source(FCVTDS, dst, src, floatFromSize(srcSize)); |
| } else { |
| fpDataProcessing1Source(FCVTSD, dst, src, floatFromSize(srcSize)); |
| } |
| } |
| |
| /* Convert to Integer (5.7.4.2) */ |
| |
| /** |
| * Convert floating point to integer. Rounds towards zero. |
| * |
| * @param targetSize size of integer register. 32 or 64. |
| * @param srcSize size of floating point register. 32 or 64. |
| * @param dst general purpose register. May not be null, the zero-register or the stackpointer. |
| * @param src floating point register. May not be null. |
| */ |
| public void fcvtzs(int targetSize, int srcSize, Register dst, Register src) { |
| assert !dst.equals(zr) && !dst.equals(sp); |
| assert src.getRegisterCategory().equals(SIMD); |
| fcvtCpuFpuInstruction(FCVTZS, dst, src, generalFromSize(targetSize), floatFromSize(srcSize)); |
| } |
| |
| /* Convert from Integer (5.7.4.2) */ |
| /** |
| * Converts integer to floating point. Uses rounding mode defined by FCPR. |
| * |
| * @param targetSize size of floating point register. 32 or 64. |
| * @param srcSize size of integer register. 32 or 64. |
| * @param dst floating point register. May not be null. |
| * @param src general purpose register. May not be null or the stackpointer. |
| */ |
| public void scvtf(int targetSize, int srcSize, Register dst, Register src) { |
| assert dst.getRegisterCategory().equals(SIMD); |
| assert !src.equals(sp); |
| fcvtCpuFpuInstruction(SCVTF, dst, src, floatFromSize(targetSize), generalFromSize(srcSize)); |
| } |
| |
| private void fcvtCpuFpuInstruction(Instruction instr, Register dst, Register src, InstructionType type1, InstructionType type2) { |
| emitInt(type1.encoding | type2.encoding | instr.encoding | FpConvertOp | rd(dst) | rs1(src)); |
| } |
| |
| /* Floating-point Round to Integral (5.7.5) */ |
| |
| /** |
| * Rounds floating-point to integral. Rounds towards zero. |
| * |
| * @param size register size. |
| * @param dst floating point register. May not be null. |
| * @param src floating point register. May not be null. |
| */ |
| protected void frintz(int size, Register dst, Register src) { |
| fpDataProcessing1Source(FRINTZ, dst, src, floatFromSize(size)); |
| } |
| |
| /* Floating-point Arithmetic (1 source) (5.7.6) */ |
| |
| /** |
| * dst = |src|. |
| * |
| * @param size register size. |
| * @param dst floating point register. May not be null. |
| * @param src floating point register. May not be null. |
| */ |
| public void fabs(int size, Register dst, Register src) { |
| fpDataProcessing1Source(FABS, dst, src, floatFromSize(size)); |
| } |
| |
| /** |
| * dst = -neg. |
| * |
| * @param size register size. |
| * @param dst floating point register. May not be null. |
| * @param src floating point register. May not be null. |
| */ |
| public void fneg(int size, Register dst, Register src) { |
| fpDataProcessing1Source(FNEG, dst, src, floatFromSize(size)); |
| } |
| |
| /** |
| * dst = Sqrt(src). |
| * |
| * @param size register size. |
| * @param dst floating point register. May not be null. |
| * @param src floating point register. May not be null. |
| */ |
| public void fsqrt(int size, Register dst, Register src) { |
| fpDataProcessing1Source(FSQRT, dst, src, floatFromSize(size)); |
| } |
| |
| private void fpDataProcessing1Source(Instruction instr, Register dst, Register src, InstructionType type) { |
| assert dst.getRegisterCategory().equals(SIMD); |
| assert src.getRegisterCategory().equals(SIMD); |
| emitInt(type.encoding | instr.encoding | Fp1SourceOp | rd(dst) | rs1(src)); |
| } |
| |
| /* Floating-point Arithmetic (2 source) (5.7.7) */ |
| |
| /** |
| * dst = src1 + src2. |
| * |
| * @param size register size. |
| * @param dst floating point register. May not be null. |
| * @param src1 floating point register. May not be null. |
| * @param src2 floating point register. May not be null. |
| */ |
| public void fadd(int size, Register dst, Register src1, Register src2) { |
| fpDataProcessing2Source(FADD, dst, src1, src2, floatFromSize(size)); |
| } |
| |
| /** |
| * dst = src1 - src2. |
| * |
| * @param size register size. |
| * @param dst floating point register. May not be null. |
| * @param src1 floating point register. May not be null. |
| * @param src2 floating point register. May not be null. |
| */ |
| public void fsub(int size, Register dst, Register src1, Register src2) { |
| fpDataProcessing2Source(FSUB, dst, src1, src2, floatFromSize(size)); |
| } |
| |
| /** |
| * dst = src1 * src2. |
| * |
| * @param size register size. |
| * @param dst floating point register. May not be null. |
| * @param src1 floating point register. May not be null. |
| * @param src2 floating point register. May not be null. |
| */ |
| public void fmul(int size, Register dst, Register src1, Register src2) { |
| fpDataProcessing2Source(FMUL, dst, src1, src2, floatFromSize(size)); |
| } |
| |
| /** |
| * dst = src1 / src2. |
| * |
| * @param size register size. |
| * @param dst floating point register. May not be null. |
| * @param src1 floating point register. May not be null. |
| * @param src2 floating point register. May not be null. |
| */ |
| public void fdiv(int size, Register dst, Register src1, Register src2) { |
| fpDataProcessing2Source(FDIV, dst, src1, src2, floatFromSize(size)); |
| } |
| |
| private void fpDataProcessing2Source(Instruction instr, Register dst, Register src1, Register src2, InstructionType type) { |
| assert dst.getRegisterCategory().equals(SIMD); |
| assert src1.getRegisterCategory().equals(SIMD); |
| assert src2.getRegisterCategory().equals(SIMD); |
| emitInt(type.encoding | instr.encoding | Fp2SourceOp | rd(dst) | rs1(src1) | rs2(src2)); |
| } |
| |
| /* Floating-point Multiply-Add (5.7.9) */ |
| |
| /** |
| * dst = src1 * src2 + src3. |
| * |
| * @param size register size. |
| * @param dst floating point register. May not be null. |
| * @param src1 floating point register. May not be null. |
| * @param src2 floating point register. May not be null. |
| * @param src3 floating point register. May not be null. |
| */ |
| protected void fmadd(int size, Register dst, Register src1, Register src2, Register src3) { |
| fpDataProcessing3Source(FMADD, dst, src1, src2, src3, floatFromSize(size)); |
| } |
| |
| /** |
| * dst = src3 - src1 * src2. |
| * |
| * @param size register size. |
| * @param dst floating point register. May not be null. |
| * @param src1 floating point register. May not be null. |
| * @param src2 floating point register. May not be null. |
| * @param src3 floating point register. May not be null. |
| */ |
| protected void fmsub(int size, Register dst, Register src1, Register src2, Register src3) { |
| fpDataProcessing3Source(FMSUB, dst, src1, src2, src3, floatFromSize(size)); |
| } |
| |
| private void fpDataProcessing3Source(Instruction instr, Register dst, Register src1, Register src2, Register src3, InstructionType type) { |
| assert dst.getRegisterCategory().equals(SIMD); |
| assert src1.getRegisterCategory().equals(SIMD); |
| assert src2.getRegisterCategory().equals(SIMD); |
| assert src3.getRegisterCategory().equals(SIMD); |
| emitInt(type.encoding | instr.encoding | Fp3SourceOp | rd(dst) | rs1(src1) | rs2(src2) | rs3(src3)); |
| } |
| |
| /* Floating-point Comparison (5.7.10) */ |
| |
| /** |
| * Compares src1 to src2. |
| * |
| * @param size register size. |
| * @param src1 floating point register. May not be null. |
| * @param src2 floating point register. May not be null. |
| */ |
| public void fcmp(int size, Register src1, Register src2) { |
| assert src1.getRegisterCategory().equals(SIMD); |
| assert src2.getRegisterCategory().equals(SIMD); |
| InstructionType type = floatFromSize(size); |
| emitInt(type.encoding | FCMP.encoding | FpCmpOp | rs1(src1) | rs2(src2)); |
| } |
| |
| /** |
| * Conditional compare. NZCV = fcmp(src1, src2) if condition else uimm4. |
| * |
| * @param size register size. |
| * @param src1 floating point register. May not be null. |
| * @param src2 floating point register. May not be null. |
| * @param uimm4 condition flags that are used if condition is false. |
| * @param condition every condition allowed. May not be null. |
| */ |
| public void fccmp(int size, Register src1, Register src2, int uimm4, ConditionFlag condition) { |
| assert NumUtil.isUnsignedNbit(4, uimm4); |
| assert src1.getRegisterCategory().equals(SIMD); |
| assert src2.getRegisterCategory().equals(SIMD); |
| InstructionType type = floatFromSize(size); |
| emitInt(type.encoding | FCCMP.encoding | uimm4 | condition.encoding << ConditionalConditionOffset | rs1(src1) | rs2(src2)); |
| } |
| |
| /** |
| * Compare register to 0.0 . |
| * |
| * @param size register size. |
| * @param src floating point register. May not be null. |
| */ |
| public void fcmpZero(int size, Register src) { |
| assert src.getRegisterCategory().equals(SIMD); |
| InstructionType type = floatFromSize(size); |
| emitInt(type.encoding | FCMPZERO.encoding | FpCmpOp | rs1(src)); |
| } |
| |
| /* Floating-point Conditional Select (5.7.11) */ |
| |
| /** |
| * Conditional select. dst = src1 if condition else src2. |
| * |
| * @param size register size. |
| * @param dst floating point register. May not be null. |
| * @param src1 floating point register. May not be null. |
| * @param src2 floating point register. May not be null. |
| * @param condition every condition allowed. May not be null. |
| */ |
| protected void fcsel(int size, Register dst, Register src1, Register src2, ConditionFlag condition) { |
| assert dst.getRegisterCategory().equals(SIMD); |
| assert src1.getRegisterCategory().equals(SIMD); |
| assert src2.getRegisterCategory().equals(SIMD); |
| InstructionType type = floatFromSize(size); |
| emitInt(type.encoding | FCSEL.encoding | rd(dst) | rs1(src1) | rs2(src2) | condition.encoding << ConditionalConditionOffset); |
| } |
| |
| /* Debug exceptions (5.9.1.2) */ |
| |
| /** |
| * Halting mode software breakpoint: Enters halting mode debug state if enabled, else treated as |
| * UNALLOCATED instruction. |
| * |
| * @param uimm16 Arbitrary 16-bit unsigned payload. |
| */ |
| protected void hlt(int uimm16) { |
| exceptionInstruction(HLT, uimm16); |
| } |
| |
| /** |
| * Monitor mode software breakpoint: exception routed to a debug monitor executing in a higher |
| * exception level. |
| * |
| * @param uimm16 Arbitrary 16-bit unsigned payload. |
| */ |
| protected void brk(int uimm16) { |
| exceptionInstruction(BRK, uimm16); |
| } |
| |
| private void exceptionInstruction(Instruction instr, int uimm16) { |
| assert NumUtil.isUnsignedNbit(16, uimm16); |
| emitInt(instr.encoding | ExceptionOp | uimm16 << SystemImmediateOffset); |
| } |
| |
| /* Architectural hints (5.9.4) */ |
| public enum SystemHint { |
| NOP(0x0), |
| YIELD(0x1), |
| WFE(0x2), |
| WFI(0x3), |
| SEV(0x4), |
| SEVL(0x5); |
| |
| private final int encoding; |
| |
| SystemHint(int encoding) { |
| this.encoding = encoding; |
| } |
| } |
| |
| /** |
| * Architectural hints. |
| * |
| * @param hint Can be any of the defined hints. May not be null. |
| */ |
| protected void hint(SystemHint hint) { |
| emitInt(HINT.encoding | hint.encoding << SystemImmediateOffset); |
| } |
| |
| /** |
| * Clear Exclusive: clears the local record of the executing processor that an address has had a |
| * request for an exclusive access. |
| */ |
| protected void clrex() { |
| emitInt(CLREX.encoding); |
| } |
| |
| /** |
| * Possible barrier definitions for Aarch64. LOAD_LOAD and LOAD_STORE map to the same underlying |
| * barrier. |
| * |
| * We only need synchronization across the inner shareable domain (see B2-90 in the Reference |
| * documentation). |
| */ |
| public enum BarrierKind { |
| LOAD_LOAD(0x9, "ISHLD"), |
| LOAD_STORE(0x9, "ISHLD"), |
| STORE_STORE(0xA, "ISHST"), |
| ANY_ANY(0xB, "ISH"); |
| |
| public final int encoding; |
| public final String optionName; |
| |
| BarrierKind(int encoding, String optionName) { |
| this.encoding = encoding; |
| this.optionName = optionName; |
| } |
| } |
| |
| /** |
| * Data Memory Barrier. |
| * |
| * @param barrierKind barrier that is issued. May not be null. |
| */ |
| public void dmb(BarrierKind barrierKind) { |
| emitInt(DMB.encoding | BarrierOp | barrierKind.encoding << BarrierKindOffset); |
| } |
| |
| } |