//===- 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_