| //===- AArch64InsnHelpers.h -----------------------------------------------===// |
| // |
| // The MCLinker Project |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| #ifndef TARGET_AARCH64_AARCH64INSNHELPERS_H_ |
| #define TARGET_AARCH64_AARCH64INSNHELPERS_H_ |
| |
| #include "mcld/Support/Compiler.h" |
| |
| namespace mcld { |
| |
| class AArch64InsnHelpers { |
| public: |
| typedef uint32_t InsnType; |
| |
| static constexpr unsigned InsnSize = 4; |
| |
| // Zero register encoding - 31. |
| static constexpr unsigned ZR = 31; |
| |
| static unsigned getBits(InsnType insn, int pos, int l) { |
| return (insn >> pos) & ((1 << l) - 1); |
| } |
| |
| static unsigned getRt(InsnType insn) { |
| return getBits(insn, 0, 5); |
| } |
| |
| static unsigned getRt2(InsnType insn) { |
| return getBits(insn, 10, 5); |
| } |
| |
| static unsigned getRa(InsnType insn) { |
| return getBits(insn, 10, 5); |
| } |
| |
| static unsigned getRd(InsnType insn) { |
| return getBits(insn, 0, 5); |
| } |
| |
| static unsigned getRn(InsnType insn) { |
| return getBits(insn, 5, 5); |
| } |
| |
| static unsigned getRm(InsnType insn) { |
| return getBits(insn, 16, 5); |
| } |
| |
| static unsigned getBit(InsnType insn, int pos) { |
| return getBits(insn, pos, 1); |
| } |
| |
| static unsigned getOp31(InsnType insn) { |
| return getBits(insn, 21, 3); |
| } |
| |
| // All ld/st ops. See C4-182 of the ARM ARM. The encoding space for LD_PCREL, |
| // LDST_RO, LDST_UI and LDST_UIMM cover prefetch ops. |
| static bool isLD(InsnType insn) { |
| return (getBit(insn, 22) == 1); |
| } |
| |
| static bool isLDST(InsnType insn) { |
| return (((insn) & 0x0a000000) == 0x08000000); |
| } |
| |
| static bool isLDSTEX(InsnType insn) { |
| return (((insn) & 0x3f000000) == 0x08000000); |
| } |
| |
| static bool isLDSTPCREL(InsnType insn) { |
| return (((insn) & 0x3b000000) == 0x18000000); |
| } |
| |
| static bool isLDSTNAP(InsnType insn) { |
| return (((insn) & 0x3b800000) == 0x28000000); |
| } |
| |
| static bool isLDSTPPI(InsnType insn) { |
| return (((insn) & 0x3b800000) == 0x28800000); |
| } |
| |
| static bool isLDSTPO(InsnType insn) { |
| return (((insn) & 0x3b800000) == 0x29000000); |
| } |
| |
| static bool isLDSTPPRE(InsnType insn) { |
| return (((insn) & 0x3b800000) == 0x29800000); |
| } |
| |
| static bool isLDSTUI(InsnType insn) { |
| return (((insn) & 0x3b200c00) == 0x38000000); |
| } |
| |
| static bool isLDSTPIIMM(InsnType insn) { |
| return (((insn) & 0x3b200c00) == 0x38000400); |
| } |
| |
| static bool isLDSTU(InsnType insn) { |
| return (((insn) & 0x3b200c00) == 0x38000800); |
| } |
| |
| static bool isLDSTPREIMM(InsnType insn) { |
| return (((insn) & 0x3b200c00) == 0x38000c00); |
| } |
| |
| static bool isLDSTRO(InsnType insn) { |
| return (((insn) & 0x3b200c00) == 0x38200800); |
| } |
| |
| static bool isLDSTUIMM(InsnType insn) { |
| return (((insn) & 0x3b000000) == 0x39000000); |
| } |
| |
| static bool isLDSTSIMDM(InsnType insn) { |
| return (((insn) & 0xbfbf0000) == 0x0c000000); |
| } |
| |
| static bool isLDSTSIMDMPI(InsnType insn) { |
| return (((insn) & 0xbfa00000) == 0x0c800000); |
| } |
| |
| static bool isLDSTSIMDS(InsnType insn) { |
| return (((insn) & 0xbf9f0000) == 0x0d000000); |
| } |
| |
| static bool isLDSTSIMDSPI(InsnType insn) { |
| return (((insn) & 0xbf800000) == 0x0d800000); |
| } |
| |
| // Return true if INSN is a mac insn. |
| static bool isMAC(InsnType insn) { |
| return (insn & 0xff000000) == 0x9b000000; |
| } |
| |
| // Return true if INSN is multiply-accumulate |
| static bool isMLXL(InsnType insn) { |
| unsigned op31 = getOp31(insn); |
| // Exclude MUL instructions which are encoded as a multiple-accumulate with |
| // RA = XZR |
| if (isMAC(insn) && |
| ((op31 == 0) || (op31 == 1) || (op31 == 5)) && |
| getRa(insn) != ZR) { |
| return true; |
| } |
| return false; |
| } |
| |
| // Classify an INSN if it is indeed a load/store. |
| // |
| // Return true if INSN is a LD/ST instruction otherwise return false. For |
| // scalar LD/ST instructions is_pair is false, rt is returned and rt2 is set |
| // equal to rt. For LD/ST pair instructions is_pair is true, rt and rt2 are |
| // returned. |
| static bool isMemOp(InsnType insn, |
| unsigned& rt, |
| unsigned& rt2, |
| bool& is_pair, |
| bool& is_load) { |
| // Bail out quickly if INSN doesn't fall into the the load-store encoding |
| // space. |
| if (!isLDST(insn)) { |
| return false; |
| } |
| |
| is_pair = false; |
| is_load = false; |
| |
| if (isLDSTEX(insn)) { |
| rt = getRt(insn); |
| rt2 = rt; |
| if (getBit(insn, 21) == 1) { |
| is_pair = true; |
| rt2 = getRt2(insn); |
| } |
| is_load = isLD(insn); |
| return true; |
| } else if (isLDSTNAP(insn) || |
| isLDSTPPI(insn) || |
| isLDSTPO(insn) || |
| isLDSTPPRE(insn)) { |
| rt = getRt(insn); |
| rt2 = getRt2(insn); |
| is_pair = true; |
| is_load = isLD(insn); |
| } else if (isLDSTPCREL(insn) || |
| isLDSTUI(insn) || |
| isLDSTPIIMM(insn) || |
| isLDSTU(insn) || |
| isLDSTPREIMM(insn) || |
| isLDSTRO(insn) || |
| isLDSTUIMM(insn)) { |
| rt = getRt(insn); |
| rt2 = rt; |
| unsigned opc = getBits(insn, 22, 2); |
| unsigned v = getBit(insn, 26); |
| unsigned opc_v = opc | (v << 2); |
| if (isLDSTPCREL(insn) || |
| ((opc_v == 1) || |
| (opc_v == 2) || |
| (opc_v == 3) || |
| (opc_v == 5) || |
| (opc_v == 7))) { |
| is_load = true; |
| } |
| return true; |
| } else if (isLDSTSIMDM(insn) || isLDSTSIMDMPI(insn)) { |
| unsigned opcode = (insn >> 12) & 0xf; |
| rt = getRt(insn); |
| is_load = (getBit(insn, 22) != 0); |
| switch (opcode) { |
| case 0: |
| case 2: { |
| rt2 = rt + 3; |
| return true; |
| } |
| case 4: |
| case 6: { |
| rt2 = rt + 2; |
| return true; |
| } |
| case 7: { |
| rt2 = rt; |
| return true; |
| } |
| case 8: |
| case 10: { |
| rt2 = rt + 1; |
| return true; |
| } |
| default: { |
| return false; |
| } |
| } // switch (opcode) |
| } else if (isLDSTSIMDS(insn) || isLDSTSIMDSPI(insn)) { |
| unsigned r = (insn >> 21) & 1; |
| unsigned opcode = (insn >> 13) & 0x7; |
| rt = getRt(insn); |
| is_load = (getBit(insn, 22) != 0); |
| switch (opcode) { |
| case 0: |
| case 2: |
| case 4: |
| case 6: { |
| rt2 = rt + r; |
| return true; |
| } |
| case 1: |
| case 3: |
| case 5: |
| case 7: { |
| rt2 = rt + ((r == 0) ? 2 : 3); |
| return true; |
| } |
| default: { |
| return false; |
| } |
| } // switch (opcode) |
| } |
| |
| return false; |
| } |
| |
| static InsnType buildBranchInsn() { |
| return 0x14000000; |
| } |
| |
| private: |
| DISALLOW_IMPLICIT_CONSTRUCTORS(AArch64InsnHelpers); |
| }; |
| |
| } // namespace mcld |
| |
| #endif // TARGET_AARCH64_AARCH64INSNHELPERS_H_ |