1 //===- AArch64InsnHelpers.h -----------------------------------------------===//
2 //
3 //                     The MCLinker Project
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 #ifndef TARGET_AARCH64_AARCH64INSNHELPERS_H_
10 #define TARGET_AARCH64_AARCH64INSNHELPERS_H_
11 
12 #include "mcld/Support/Compiler.h"
13 
14 namespace mcld {
15 
16 class AArch64InsnHelpers {
17  public:
18   typedef uint32_t InsnType;
19 
20   static constexpr unsigned InsnSize = 4;
21 
22   // Zero register encoding - 31.
23   static constexpr unsigned ZR = 31;
24 
getBits(InsnType insn,int pos,int l)25   static unsigned getBits(InsnType insn, int pos, int l) {
26     return (insn >> pos) & ((1 << l) - 1);
27   }
28 
getRt(InsnType insn)29   static unsigned getRt(InsnType insn) {
30     return getBits(insn, 0, 5);
31   }
32 
getRt2(InsnType insn)33   static unsigned getRt2(InsnType insn) {
34     return getBits(insn, 10, 5);
35   }
36 
getRa(InsnType insn)37   static unsigned getRa(InsnType insn) {
38     return getBits(insn, 10, 5);
39   }
40 
getRd(InsnType insn)41   static unsigned getRd(InsnType insn) {
42     return getBits(insn, 0, 5);
43   }
44 
getRn(InsnType insn)45   static unsigned getRn(InsnType insn) {
46     return getBits(insn, 5, 5);
47   }
48 
getRm(InsnType insn)49   static unsigned getRm(InsnType insn) {
50     return getBits(insn, 16, 5);
51   }
52 
getBit(InsnType insn,int pos)53   static unsigned getBit(InsnType insn, int pos) {
54     return getBits(insn, pos, 1);
55   }
56 
getOp31(InsnType insn)57   static unsigned getOp31(InsnType insn) {
58     return getBits(insn, 21, 3);
59   }
60 
61   // All ld/st ops. See C4-182 of the ARM ARM. The encoding space for LD_PCREL,
62   // LDST_RO, LDST_UI and LDST_UIMM cover prefetch ops.
isLD(InsnType insn)63   static bool isLD(InsnType insn) {
64     return (getBit(insn, 22) == 1);
65   }
66 
isLDST(InsnType insn)67   static bool isLDST(InsnType insn) {
68     return (((insn) & 0x0a000000) == 0x08000000);
69   }
70 
isLDSTEX(InsnType insn)71   static bool isLDSTEX(InsnType insn) {
72     return (((insn) & 0x3f000000) == 0x08000000);
73   }
74 
isLDSTPCREL(InsnType insn)75   static bool isLDSTPCREL(InsnType insn) {
76     return (((insn) & 0x3b000000) == 0x18000000);
77   }
78 
isLDSTNAP(InsnType insn)79   static bool isLDSTNAP(InsnType insn) {
80     return (((insn) & 0x3b800000) == 0x28000000);
81   }
82 
isLDSTPPI(InsnType insn)83   static bool isLDSTPPI(InsnType insn) {
84     return (((insn) & 0x3b800000) == 0x28800000);
85   }
86 
isLDSTPO(InsnType insn)87   static bool isLDSTPO(InsnType insn) {
88     return (((insn) & 0x3b800000) == 0x29000000);
89   }
90 
isLDSTPPRE(InsnType insn)91   static bool isLDSTPPRE(InsnType insn) {
92     return (((insn) & 0x3b800000) == 0x29800000);
93   }
94 
isLDSTUI(InsnType insn)95   static bool isLDSTUI(InsnType insn) {
96     return (((insn) & 0x3b200c00) == 0x38000000);
97   }
98 
isLDSTPIIMM(InsnType insn)99   static bool isLDSTPIIMM(InsnType insn) {
100     return (((insn) & 0x3b200c00) == 0x38000400);
101   }
102 
isLDSTU(InsnType insn)103   static bool isLDSTU(InsnType insn) {
104     return (((insn) & 0x3b200c00) == 0x38000800);
105   }
106 
isLDSTPREIMM(InsnType insn)107   static bool isLDSTPREIMM(InsnType insn) {
108     return (((insn) & 0x3b200c00) == 0x38000c00);
109   }
110 
isLDSTRO(InsnType insn)111   static bool isLDSTRO(InsnType insn) {
112     return (((insn) & 0x3b200c00) == 0x38200800);
113   }
114 
isLDSTUIMM(InsnType insn)115   static bool isLDSTUIMM(InsnType insn) {
116     return (((insn) & 0x3b000000) == 0x39000000);
117   }
118 
isLDSTSIMDM(InsnType insn)119   static bool isLDSTSIMDM(InsnType insn) {
120     return (((insn) & 0xbfbf0000) == 0x0c000000);
121   }
122 
isLDSTSIMDMPI(InsnType insn)123   static bool isLDSTSIMDMPI(InsnType insn) {
124     return (((insn) & 0xbfa00000) == 0x0c800000);
125   }
126 
isLDSTSIMDS(InsnType insn)127   static bool isLDSTSIMDS(InsnType insn) {
128     return (((insn) & 0xbf9f0000) == 0x0d000000);
129   }
130 
isLDSTSIMDSPI(InsnType insn)131   static bool isLDSTSIMDSPI(InsnType insn) {
132     return (((insn) & 0xbf800000) == 0x0d800000);
133   }
134 
135   // Return true if INSN is a mac insn.
isMAC(InsnType insn)136   static bool isMAC(InsnType insn) {
137     return (insn & 0xff000000) == 0x9b000000;
138   }
139 
140   // Return true if INSN is multiply-accumulate
isMLXL(InsnType insn)141   static bool isMLXL(InsnType insn) {
142     unsigned op31 = getOp31(insn);
143     // Exclude MUL instructions which are encoded as a multiple-accumulate with
144     // RA = XZR
145     if (isMAC(insn) &&
146         ((op31 == 0) || (op31 == 1) || (op31 == 5)) &&
147         getRa(insn) != ZR) {
148       return true;
149     }
150     return false;
151   }
152 
153   // Classify an INSN if it is indeed a load/store.
154   //
155   // Return true if INSN is a LD/ST instruction otherwise return false. For
156   // scalar LD/ST instructions is_pair is false, rt is returned and rt2 is set
157   // equal to rt. For LD/ST pair instructions is_pair is true, rt and rt2 are
158   // returned.
isMemOp(InsnType insn,unsigned & rt,unsigned & rt2,bool & is_pair,bool & is_load)159   static bool isMemOp(InsnType insn,
160                       unsigned& rt,
161                       unsigned& rt2,
162                       bool& is_pair,
163                       bool& is_load) {
164     // Bail out quickly if INSN doesn't fall into the the load-store encoding
165     // space.
166     if (!isLDST(insn)) {
167       return false;
168     }
169 
170     is_pair = false;
171     is_load = false;
172 
173     if (isLDSTEX(insn)) {
174       rt = getRt(insn);
175       rt2 = rt;
176       if (getBit(insn, 21) == 1) {
177         is_pair = true;
178         rt2 = getRt2(insn);
179       }
180       is_load = isLD(insn);
181       return true;
182     } else if (isLDSTNAP(insn) ||
183                isLDSTPPI(insn) ||
184                isLDSTPO(insn) ||
185                isLDSTPPRE(insn)) {
186       rt = getRt(insn);
187       rt2 = getRt2(insn);
188       is_pair = true;
189       is_load = isLD(insn);
190     } else if (isLDSTPCREL(insn) ||
191                isLDSTUI(insn) ||
192                isLDSTPIIMM(insn) ||
193                isLDSTU(insn) ||
194                isLDSTPREIMM(insn) ||
195                isLDSTRO(insn) ||
196                isLDSTUIMM(insn)) {
197       rt = getRt(insn);
198       rt2 = rt;
199       unsigned opc = getBits(insn, 22, 2);
200       unsigned v = getBit(insn, 26);
201       unsigned opc_v = opc | (v << 2);
202       if (isLDSTPCREL(insn) ||
203           ((opc_v == 1) ||
204            (opc_v == 2) ||
205            (opc_v == 3) ||
206            (opc_v == 5) ||
207            (opc_v == 7))) {
208         is_load = true;
209       }
210       return true;
211     } else if (isLDSTSIMDM(insn) || isLDSTSIMDMPI(insn)) {
212       unsigned opcode = (insn >> 12) & 0xf;
213       rt = getRt(insn);
214       is_load = (getBit(insn, 22) != 0);
215       switch (opcode) {
216         case 0:
217         case 2: {
218           rt2 = rt + 3;
219           return true;
220         }
221         case 4:
222         case 6: {
223           rt2 = rt + 2;
224           return true;
225         }
226         case 7: {
227           rt2 = rt;
228           return true;
229         }
230         case 8:
231         case 10: {
232           rt2 = rt + 1;
233           return true;
234         }
235         default: {
236           return false;
237         }
238       }  // switch (opcode)
239     } else if (isLDSTSIMDS(insn) || isLDSTSIMDSPI(insn)) {
240       unsigned r = (insn >> 21) & 1;
241       unsigned opcode = (insn >> 13) & 0x7;
242       rt = getRt(insn);
243       is_load = (getBit(insn, 22) != 0);
244       switch (opcode) {
245         case 0:
246         case 2:
247         case 4:
248         case 6: {
249           rt2 = rt + r;
250           return true;
251         }
252         case 1:
253         case 3:
254         case 5:
255         case 7: {
256           rt2 = rt + ((r == 0) ? 2 : 3);
257           return true;
258         }
259         default: {
260           return false;
261         }
262       }  // switch (opcode)
263     }
264 
265     return false;
266   }
267 
buildBranchInsn()268   static InsnType buildBranchInsn() {
269     return 0x14000000;
270   }
271 
272  private:
273   DISALLOW_IMPLICIT_CONSTRUCTORS(AArch64InsnHelpers);
274 };
275 
276 }  // namespace mcld
277 
278 #endif  // TARGET_AARCH64_AARCH64INSNHELPERS_H_
279