xref: /aosp_15_r20/external/llvm/lib/Target/ARM/MCTargetDesc/ARMAddressingModes.h (revision 9880d6810fe72a1726cb53787c6711e909410d58)
1*9880d681SAndroid Build Coastguard Worker //===-- ARMAddressingModes.h - ARM Addressing Modes -------------*- C++ -*-===//
2*9880d681SAndroid Build Coastguard Worker //
3*9880d681SAndroid Build Coastguard Worker //                     The LLVM Compiler Infrastructure
4*9880d681SAndroid Build Coastguard Worker //
5*9880d681SAndroid Build Coastguard Worker // This file is distributed under the University of Illinois Open Source
6*9880d681SAndroid Build Coastguard Worker // License. See LICENSE.TXT for details.
7*9880d681SAndroid Build Coastguard Worker //
8*9880d681SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
9*9880d681SAndroid Build Coastguard Worker //
10*9880d681SAndroid Build Coastguard Worker // This file contains the ARM addressing mode implementation stuff.
11*9880d681SAndroid Build Coastguard Worker //
12*9880d681SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
13*9880d681SAndroid Build Coastguard Worker 
14*9880d681SAndroid Build Coastguard Worker #ifndef LLVM_LIB_TARGET_ARM_MCTARGETDESC_ARMADDRESSINGMODES_H
15*9880d681SAndroid Build Coastguard Worker #define LLVM_LIB_TARGET_ARM_MCTARGETDESC_ARMADDRESSINGMODES_H
16*9880d681SAndroid Build Coastguard Worker 
17*9880d681SAndroid Build Coastguard Worker #include "llvm/ADT/APFloat.h"
18*9880d681SAndroid Build Coastguard Worker #include "llvm/ADT/APInt.h"
19*9880d681SAndroid Build Coastguard Worker #include "llvm/Support/ErrorHandling.h"
20*9880d681SAndroid Build Coastguard Worker #include "llvm/Support/MathExtras.h"
21*9880d681SAndroid Build Coastguard Worker #include <cassert>
22*9880d681SAndroid Build Coastguard Worker 
23*9880d681SAndroid Build Coastguard Worker namespace llvm {
24*9880d681SAndroid Build Coastguard Worker 
25*9880d681SAndroid Build Coastguard Worker /// ARM_AM - ARM Addressing Mode Stuff
26*9880d681SAndroid Build Coastguard Worker namespace ARM_AM {
27*9880d681SAndroid Build Coastguard Worker   enum ShiftOpc {
28*9880d681SAndroid Build Coastguard Worker     no_shift = 0,
29*9880d681SAndroid Build Coastguard Worker     asr,
30*9880d681SAndroid Build Coastguard Worker     lsl,
31*9880d681SAndroid Build Coastguard Worker     lsr,
32*9880d681SAndroid Build Coastguard Worker     ror,
33*9880d681SAndroid Build Coastguard Worker     rrx
34*9880d681SAndroid Build Coastguard Worker   };
35*9880d681SAndroid Build Coastguard Worker 
36*9880d681SAndroid Build Coastguard Worker   enum AddrOpc {
37*9880d681SAndroid Build Coastguard Worker     sub = 0,
38*9880d681SAndroid Build Coastguard Worker     add
39*9880d681SAndroid Build Coastguard Worker   };
40*9880d681SAndroid Build Coastguard Worker 
getAddrOpcStr(AddrOpc Op)41*9880d681SAndroid Build Coastguard Worker   static inline const char *getAddrOpcStr(AddrOpc Op) {
42*9880d681SAndroid Build Coastguard Worker     return Op == sub ? "-" : "";
43*9880d681SAndroid Build Coastguard Worker   }
44*9880d681SAndroid Build Coastguard Worker 
getShiftOpcStr(ShiftOpc Op)45*9880d681SAndroid Build Coastguard Worker   static inline const char *getShiftOpcStr(ShiftOpc Op) {
46*9880d681SAndroid Build Coastguard Worker     switch (Op) {
47*9880d681SAndroid Build Coastguard Worker     default: llvm_unreachable("Unknown shift opc!");
48*9880d681SAndroid Build Coastguard Worker     case ARM_AM::asr: return "asr";
49*9880d681SAndroid Build Coastguard Worker     case ARM_AM::lsl: return "lsl";
50*9880d681SAndroid Build Coastguard Worker     case ARM_AM::lsr: return "lsr";
51*9880d681SAndroid Build Coastguard Worker     case ARM_AM::ror: return "ror";
52*9880d681SAndroid Build Coastguard Worker     case ARM_AM::rrx: return "rrx";
53*9880d681SAndroid Build Coastguard Worker     }
54*9880d681SAndroid Build Coastguard Worker   }
55*9880d681SAndroid Build Coastguard Worker 
getShiftOpcEncoding(ShiftOpc Op)56*9880d681SAndroid Build Coastguard Worker   static inline unsigned getShiftOpcEncoding(ShiftOpc Op) {
57*9880d681SAndroid Build Coastguard Worker     switch (Op) {
58*9880d681SAndroid Build Coastguard Worker     default: llvm_unreachable("Unknown shift opc!");
59*9880d681SAndroid Build Coastguard Worker     case ARM_AM::asr: return 2;
60*9880d681SAndroid Build Coastguard Worker     case ARM_AM::lsl: return 0;
61*9880d681SAndroid Build Coastguard Worker     case ARM_AM::lsr: return 1;
62*9880d681SAndroid Build Coastguard Worker     case ARM_AM::ror: return 3;
63*9880d681SAndroid Build Coastguard Worker     }
64*9880d681SAndroid Build Coastguard Worker   }
65*9880d681SAndroid Build Coastguard Worker 
66*9880d681SAndroid Build Coastguard Worker   enum AMSubMode {
67*9880d681SAndroid Build Coastguard Worker     bad_am_submode = 0,
68*9880d681SAndroid Build Coastguard Worker     ia,
69*9880d681SAndroid Build Coastguard Worker     ib,
70*9880d681SAndroid Build Coastguard Worker     da,
71*9880d681SAndroid Build Coastguard Worker     db
72*9880d681SAndroid Build Coastguard Worker   };
73*9880d681SAndroid Build Coastguard Worker 
getAMSubModeStr(AMSubMode Mode)74*9880d681SAndroid Build Coastguard Worker   static inline const char *getAMSubModeStr(AMSubMode Mode) {
75*9880d681SAndroid Build Coastguard Worker     switch (Mode) {
76*9880d681SAndroid Build Coastguard Worker     default: llvm_unreachable("Unknown addressing sub-mode!");
77*9880d681SAndroid Build Coastguard Worker     case ARM_AM::ia: return "ia";
78*9880d681SAndroid Build Coastguard Worker     case ARM_AM::ib: return "ib";
79*9880d681SAndroid Build Coastguard Worker     case ARM_AM::da: return "da";
80*9880d681SAndroid Build Coastguard Worker     case ARM_AM::db: return "db";
81*9880d681SAndroid Build Coastguard Worker     }
82*9880d681SAndroid Build Coastguard Worker   }
83*9880d681SAndroid Build Coastguard Worker 
84*9880d681SAndroid Build Coastguard Worker   /// rotr32 - Rotate a 32-bit unsigned value right by a specified # bits.
85*9880d681SAndroid Build Coastguard Worker   ///
rotr32(unsigned Val,unsigned Amt)86*9880d681SAndroid Build Coastguard Worker   static inline unsigned rotr32(unsigned Val, unsigned Amt) {
87*9880d681SAndroid Build Coastguard Worker     assert(Amt < 32 && "Invalid rotate amount");
88*9880d681SAndroid Build Coastguard Worker     return (Val >> Amt) | (Val << ((32-Amt)&31));
89*9880d681SAndroid Build Coastguard Worker   }
90*9880d681SAndroid Build Coastguard Worker 
91*9880d681SAndroid Build Coastguard Worker   /// rotl32 - Rotate a 32-bit unsigned value left by a specified # bits.
92*9880d681SAndroid Build Coastguard Worker   ///
rotl32(unsigned Val,unsigned Amt)93*9880d681SAndroid Build Coastguard Worker   static inline unsigned rotl32(unsigned Val, unsigned Amt) {
94*9880d681SAndroid Build Coastguard Worker     assert(Amt < 32 && "Invalid rotate amount");
95*9880d681SAndroid Build Coastguard Worker     return (Val << Amt) | (Val >> ((32-Amt)&31));
96*9880d681SAndroid Build Coastguard Worker   }
97*9880d681SAndroid Build Coastguard Worker 
98*9880d681SAndroid Build Coastguard Worker   //===--------------------------------------------------------------------===//
99*9880d681SAndroid Build Coastguard Worker   // Addressing Mode #1: shift_operand with registers
100*9880d681SAndroid Build Coastguard Worker   //===--------------------------------------------------------------------===//
101*9880d681SAndroid Build Coastguard Worker   //
102*9880d681SAndroid Build Coastguard Worker   // This 'addressing mode' is used for arithmetic instructions.  It can
103*9880d681SAndroid Build Coastguard Worker   // represent things like:
104*9880d681SAndroid Build Coastguard Worker   //   reg
105*9880d681SAndroid Build Coastguard Worker   //   reg [asr|lsl|lsr|ror|rrx] reg
106*9880d681SAndroid Build Coastguard Worker   //   reg [asr|lsl|lsr|ror|rrx] imm
107*9880d681SAndroid Build Coastguard Worker   //
108*9880d681SAndroid Build Coastguard Worker   // This is stored three operands [rega, regb, opc].  The first is the base
109*9880d681SAndroid Build Coastguard Worker   // reg, the second is the shift amount (or reg0 if not present or imm).  The
110*9880d681SAndroid Build Coastguard Worker   // third operand encodes the shift opcode and the imm if a reg isn't present.
111*9880d681SAndroid Build Coastguard Worker   //
getSORegOpc(ShiftOpc ShOp,unsigned Imm)112*9880d681SAndroid Build Coastguard Worker   static inline unsigned getSORegOpc(ShiftOpc ShOp, unsigned Imm) {
113*9880d681SAndroid Build Coastguard Worker     return ShOp | (Imm << 3);
114*9880d681SAndroid Build Coastguard Worker   }
getSORegOffset(unsigned Op)115*9880d681SAndroid Build Coastguard Worker   static inline unsigned getSORegOffset(unsigned Op) {
116*9880d681SAndroid Build Coastguard Worker     return Op >> 3;
117*9880d681SAndroid Build Coastguard Worker   }
getSORegShOp(unsigned Op)118*9880d681SAndroid Build Coastguard Worker   static inline ShiftOpc getSORegShOp(unsigned Op) {
119*9880d681SAndroid Build Coastguard Worker     return (ShiftOpc)(Op & 7);
120*9880d681SAndroid Build Coastguard Worker   }
121*9880d681SAndroid Build Coastguard Worker 
122*9880d681SAndroid Build Coastguard Worker   /// getSOImmValImm - Given an encoded imm field for the reg/imm form, return
123*9880d681SAndroid Build Coastguard Worker   /// the 8-bit imm value.
getSOImmValImm(unsigned Imm)124*9880d681SAndroid Build Coastguard Worker   static inline unsigned getSOImmValImm(unsigned Imm) {
125*9880d681SAndroid Build Coastguard Worker     return Imm & 0xFF;
126*9880d681SAndroid Build Coastguard Worker   }
127*9880d681SAndroid Build Coastguard Worker   /// getSOImmValRot - Given an encoded imm field for the reg/imm form, return
128*9880d681SAndroid Build Coastguard Worker   /// the rotate amount.
getSOImmValRot(unsigned Imm)129*9880d681SAndroid Build Coastguard Worker   static inline unsigned getSOImmValRot(unsigned Imm) {
130*9880d681SAndroid Build Coastguard Worker     return (Imm >> 8) * 2;
131*9880d681SAndroid Build Coastguard Worker   }
132*9880d681SAndroid Build Coastguard Worker 
133*9880d681SAndroid Build Coastguard Worker   /// getSOImmValRotate - Try to handle Imm with an immediate shifter operand,
134*9880d681SAndroid Build Coastguard Worker   /// computing the rotate amount to use.  If this immediate value cannot be
135*9880d681SAndroid Build Coastguard Worker   /// handled with a single shifter-op, determine a good rotate amount that will
136*9880d681SAndroid Build Coastguard Worker   /// take a maximal chunk of bits out of the immediate.
getSOImmValRotate(unsigned Imm)137*9880d681SAndroid Build Coastguard Worker   static inline unsigned getSOImmValRotate(unsigned Imm) {
138*9880d681SAndroid Build Coastguard Worker     // 8-bit (or less) immediates are trivially shifter_operands with a rotate
139*9880d681SAndroid Build Coastguard Worker     // of zero.
140*9880d681SAndroid Build Coastguard Worker     if ((Imm & ~255U) == 0) return 0;
141*9880d681SAndroid Build Coastguard Worker 
142*9880d681SAndroid Build Coastguard Worker     // Use CTZ to compute the rotate amount.
143*9880d681SAndroid Build Coastguard Worker     unsigned TZ = countTrailingZeros(Imm);
144*9880d681SAndroid Build Coastguard Worker 
145*9880d681SAndroid Build Coastguard Worker     // Rotate amount must be even.  Something like 0x200 must be rotated 8 bits,
146*9880d681SAndroid Build Coastguard Worker     // not 9.
147*9880d681SAndroid Build Coastguard Worker     unsigned RotAmt = TZ & ~1;
148*9880d681SAndroid Build Coastguard Worker 
149*9880d681SAndroid Build Coastguard Worker     // If we can handle this spread, return it.
150*9880d681SAndroid Build Coastguard Worker     if ((rotr32(Imm, RotAmt) & ~255U) == 0)
151*9880d681SAndroid Build Coastguard Worker       return (32-RotAmt)&31;  // HW rotates right, not left.
152*9880d681SAndroid Build Coastguard Worker 
153*9880d681SAndroid Build Coastguard Worker     // For values like 0xF000000F, we should ignore the low 6 bits, then
154*9880d681SAndroid Build Coastguard Worker     // retry the hunt.
155*9880d681SAndroid Build Coastguard Worker     if (Imm & 63U) {
156*9880d681SAndroid Build Coastguard Worker       unsigned TZ2 = countTrailingZeros(Imm & ~63U);
157*9880d681SAndroid Build Coastguard Worker       unsigned RotAmt2 = TZ2 & ~1;
158*9880d681SAndroid Build Coastguard Worker       if ((rotr32(Imm, RotAmt2) & ~255U) == 0)
159*9880d681SAndroid Build Coastguard Worker         return (32-RotAmt2)&31;  // HW rotates right, not left.
160*9880d681SAndroid Build Coastguard Worker     }
161*9880d681SAndroid Build Coastguard Worker 
162*9880d681SAndroid Build Coastguard Worker     // Otherwise, we have no way to cover this span of bits with a single
163*9880d681SAndroid Build Coastguard Worker     // shifter_op immediate.  Return a chunk of bits that will be useful to
164*9880d681SAndroid Build Coastguard Worker     // handle.
165*9880d681SAndroid Build Coastguard Worker     return (32-RotAmt)&31;  // HW rotates right, not left.
166*9880d681SAndroid Build Coastguard Worker   }
167*9880d681SAndroid Build Coastguard Worker 
168*9880d681SAndroid Build Coastguard Worker   /// getSOImmVal - Given a 32-bit immediate, if it is something that can fit
169*9880d681SAndroid Build Coastguard Worker   /// into an shifter_operand immediate operand, return the 12-bit encoding for
170*9880d681SAndroid Build Coastguard Worker   /// it.  If not, return -1.
getSOImmVal(unsigned Arg)171*9880d681SAndroid Build Coastguard Worker   static inline int getSOImmVal(unsigned Arg) {
172*9880d681SAndroid Build Coastguard Worker     // 8-bit (or less) immediates are trivially shifter_operands with a rotate
173*9880d681SAndroid Build Coastguard Worker     // of zero.
174*9880d681SAndroid Build Coastguard Worker     if ((Arg & ~255U) == 0) return Arg;
175*9880d681SAndroid Build Coastguard Worker 
176*9880d681SAndroid Build Coastguard Worker     unsigned RotAmt = getSOImmValRotate(Arg);
177*9880d681SAndroid Build Coastguard Worker 
178*9880d681SAndroid Build Coastguard Worker     // If this cannot be handled with a single shifter_op, bail out.
179*9880d681SAndroid Build Coastguard Worker     if (rotr32(~255U, RotAmt) & Arg)
180*9880d681SAndroid Build Coastguard Worker       return -1;
181*9880d681SAndroid Build Coastguard Worker 
182*9880d681SAndroid Build Coastguard Worker     // Encode this correctly.
183*9880d681SAndroid Build Coastguard Worker     return rotl32(Arg, RotAmt) | ((RotAmt>>1) << 8);
184*9880d681SAndroid Build Coastguard Worker   }
185*9880d681SAndroid Build Coastguard Worker 
186*9880d681SAndroid Build Coastguard Worker   /// isSOImmTwoPartVal - Return true if the specified value can be obtained by
187*9880d681SAndroid Build Coastguard Worker   /// or'ing together two SOImmVal's.
isSOImmTwoPartVal(unsigned V)188*9880d681SAndroid Build Coastguard Worker   static inline bool isSOImmTwoPartVal(unsigned V) {
189*9880d681SAndroid Build Coastguard Worker     // If this can be handled with a single shifter_op, bail out.
190*9880d681SAndroid Build Coastguard Worker     V = rotr32(~255U, getSOImmValRotate(V)) & V;
191*9880d681SAndroid Build Coastguard Worker     if (V == 0)
192*9880d681SAndroid Build Coastguard Worker       return false;
193*9880d681SAndroid Build Coastguard Worker 
194*9880d681SAndroid Build Coastguard Worker     // If this can be handled with two shifter_op's, accept.
195*9880d681SAndroid Build Coastguard Worker     V = rotr32(~255U, getSOImmValRotate(V)) & V;
196*9880d681SAndroid Build Coastguard Worker     return V == 0;
197*9880d681SAndroid Build Coastguard Worker   }
198*9880d681SAndroid Build Coastguard Worker 
199*9880d681SAndroid Build Coastguard Worker   /// getSOImmTwoPartFirst - If V is a value that satisfies isSOImmTwoPartVal,
200*9880d681SAndroid Build Coastguard Worker   /// return the first chunk of it.
getSOImmTwoPartFirst(unsigned V)201*9880d681SAndroid Build Coastguard Worker   static inline unsigned getSOImmTwoPartFirst(unsigned V) {
202*9880d681SAndroid Build Coastguard Worker     return rotr32(255U, getSOImmValRotate(V)) & V;
203*9880d681SAndroid Build Coastguard Worker   }
204*9880d681SAndroid Build Coastguard Worker 
205*9880d681SAndroid Build Coastguard Worker   /// getSOImmTwoPartSecond - If V is a value that satisfies isSOImmTwoPartVal,
206*9880d681SAndroid Build Coastguard Worker   /// return the second chunk of it.
getSOImmTwoPartSecond(unsigned V)207*9880d681SAndroid Build Coastguard Worker   static inline unsigned getSOImmTwoPartSecond(unsigned V) {
208*9880d681SAndroid Build Coastguard Worker     // Mask out the first hunk.
209*9880d681SAndroid Build Coastguard Worker     V = rotr32(~255U, getSOImmValRotate(V)) & V;
210*9880d681SAndroid Build Coastguard Worker 
211*9880d681SAndroid Build Coastguard Worker     // Take what's left.
212*9880d681SAndroid Build Coastguard Worker     assert(V == (rotr32(255U, getSOImmValRotate(V)) & V));
213*9880d681SAndroid Build Coastguard Worker     return V;
214*9880d681SAndroid Build Coastguard Worker   }
215*9880d681SAndroid Build Coastguard Worker 
216*9880d681SAndroid Build Coastguard Worker   /// getThumbImmValShift - Try to handle Imm with a 8-bit immediate followed
217*9880d681SAndroid Build Coastguard Worker   /// by a left shift. Returns the shift amount to use.
getThumbImmValShift(unsigned Imm)218*9880d681SAndroid Build Coastguard Worker   static inline unsigned getThumbImmValShift(unsigned Imm) {
219*9880d681SAndroid Build Coastguard Worker     // 8-bit (or less) immediates are trivially immediate operand with a shift
220*9880d681SAndroid Build Coastguard Worker     // of zero.
221*9880d681SAndroid Build Coastguard Worker     if ((Imm & ~255U) == 0) return 0;
222*9880d681SAndroid Build Coastguard Worker 
223*9880d681SAndroid Build Coastguard Worker     // Use CTZ to compute the shift amount.
224*9880d681SAndroid Build Coastguard Worker     return countTrailingZeros(Imm);
225*9880d681SAndroid Build Coastguard Worker   }
226*9880d681SAndroid Build Coastguard Worker 
227*9880d681SAndroid Build Coastguard Worker   /// isThumbImmShiftedVal - Return true if the specified value can be obtained
228*9880d681SAndroid Build Coastguard Worker   /// by left shifting a 8-bit immediate.
isThumbImmShiftedVal(unsigned V)229*9880d681SAndroid Build Coastguard Worker   static inline bool isThumbImmShiftedVal(unsigned V) {
230*9880d681SAndroid Build Coastguard Worker     // If this can be handled with
231*9880d681SAndroid Build Coastguard Worker     V = (~255U << getThumbImmValShift(V)) & V;
232*9880d681SAndroid Build Coastguard Worker     return V == 0;
233*9880d681SAndroid Build Coastguard Worker   }
234*9880d681SAndroid Build Coastguard Worker 
235*9880d681SAndroid Build Coastguard Worker   /// getThumbImm16ValShift - Try to handle Imm with a 16-bit immediate followed
236*9880d681SAndroid Build Coastguard Worker   /// by a left shift. Returns the shift amount to use.
getThumbImm16ValShift(unsigned Imm)237*9880d681SAndroid Build Coastguard Worker   static inline unsigned getThumbImm16ValShift(unsigned Imm) {
238*9880d681SAndroid Build Coastguard Worker     // 16-bit (or less) immediates are trivially immediate operand with a shift
239*9880d681SAndroid Build Coastguard Worker     // of zero.
240*9880d681SAndroid Build Coastguard Worker     if ((Imm & ~65535U) == 0) return 0;
241*9880d681SAndroid Build Coastguard Worker 
242*9880d681SAndroid Build Coastguard Worker     // Use CTZ to compute the shift amount.
243*9880d681SAndroid Build Coastguard Worker     return countTrailingZeros(Imm);
244*9880d681SAndroid Build Coastguard Worker   }
245*9880d681SAndroid Build Coastguard Worker 
246*9880d681SAndroid Build Coastguard Worker   /// isThumbImm16ShiftedVal - Return true if the specified value can be
247*9880d681SAndroid Build Coastguard Worker   /// obtained by left shifting a 16-bit immediate.
isThumbImm16ShiftedVal(unsigned V)248*9880d681SAndroid Build Coastguard Worker   static inline bool isThumbImm16ShiftedVal(unsigned V) {
249*9880d681SAndroid Build Coastguard Worker     // If this can be handled with
250*9880d681SAndroid Build Coastguard Worker     V = (~65535U << getThumbImm16ValShift(V)) & V;
251*9880d681SAndroid Build Coastguard Worker     return V == 0;
252*9880d681SAndroid Build Coastguard Worker   }
253*9880d681SAndroid Build Coastguard Worker 
254*9880d681SAndroid Build Coastguard Worker   /// getThumbImmNonShiftedVal - If V is a value that satisfies
255*9880d681SAndroid Build Coastguard Worker   /// isThumbImmShiftedVal, return the non-shiftd value.
getThumbImmNonShiftedVal(unsigned V)256*9880d681SAndroid Build Coastguard Worker   static inline unsigned getThumbImmNonShiftedVal(unsigned V) {
257*9880d681SAndroid Build Coastguard Worker     return V >> getThumbImmValShift(V);
258*9880d681SAndroid Build Coastguard Worker   }
259*9880d681SAndroid Build Coastguard Worker 
260*9880d681SAndroid Build Coastguard Worker 
261*9880d681SAndroid Build Coastguard Worker   /// getT2SOImmValSplat - Return the 12-bit encoded representation
262*9880d681SAndroid Build Coastguard Worker   /// if the specified value can be obtained by splatting the low 8 bits
263*9880d681SAndroid Build Coastguard Worker   /// into every other byte or every byte of a 32-bit value. i.e.,
264*9880d681SAndroid Build Coastguard Worker   ///     00000000 00000000 00000000 abcdefgh    control = 0
265*9880d681SAndroid Build Coastguard Worker   ///     00000000 abcdefgh 00000000 abcdefgh    control = 1
266*9880d681SAndroid Build Coastguard Worker   ///     abcdefgh 00000000 abcdefgh 00000000    control = 2
267*9880d681SAndroid Build Coastguard Worker   ///     abcdefgh abcdefgh abcdefgh abcdefgh    control = 3
268*9880d681SAndroid Build Coastguard Worker   /// Return -1 if none of the above apply.
269*9880d681SAndroid Build Coastguard Worker   /// See ARM Reference Manual A6.3.2.
getT2SOImmValSplatVal(unsigned V)270*9880d681SAndroid Build Coastguard Worker   static inline int getT2SOImmValSplatVal(unsigned V) {
271*9880d681SAndroid Build Coastguard Worker     unsigned u, Vs, Imm;
272*9880d681SAndroid Build Coastguard Worker     // control = 0
273*9880d681SAndroid Build Coastguard Worker     if ((V & 0xffffff00) == 0)
274*9880d681SAndroid Build Coastguard Worker       return V;
275*9880d681SAndroid Build Coastguard Worker 
276*9880d681SAndroid Build Coastguard Worker     // If the value is zeroes in the first byte, just shift those off
277*9880d681SAndroid Build Coastguard Worker     Vs = ((V & 0xff) == 0) ? V >> 8 : V;
278*9880d681SAndroid Build Coastguard Worker     // Any passing value only has 8 bits of payload, splatted across the word
279*9880d681SAndroid Build Coastguard Worker     Imm = Vs & 0xff;
280*9880d681SAndroid Build Coastguard Worker     // Likewise, any passing values have the payload splatted into the 3rd byte
281*9880d681SAndroid Build Coastguard Worker     u = Imm | (Imm << 16);
282*9880d681SAndroid Build Coastguard Worker 
283*9880d681SAndroid Build Coastguard Worker     // control = 1 or 2
284*9880d681SAndroid Build Coastguard Worker     if (Vs == u)
285*9880d681SAndroid Build Coastguard Worker       return (((Vs == V) ? 1 : 2) << 8) | Imm;
286*9880d681SAndroid Build Coastguard Worker 
287*9880d681SAndroid Build Coastguard Worker     // control = 3
288*9880d681SAndroid Build Coastguard Worker     if (Vs == (u | (u << 8)))
289*9880d681SAndroid Build Coastguard Worker       return (3 << 8) | Imm;
290*9880d681SAndroid Build Coastguard Worker 
291*9880d681SAndroid Build Coastguard Worker     return -1;
292*9880d681SAndroid Build Coastguard Worker   }
293*9880d681SAndroid Build Coastguard Worker 
294*9880d681SAndroid Build Coastguard Worker   /// getT2SOImmValRotateVal - Return the 12-bit encoded representation if the
295*9880d681SAndroid Build Coastguard Worker   /// specified value is a rotated 8-bit value. Return -1 if no rotation
296*9880d681SAndroid Build Coastguard Worker   /// encoding is possible.
297*9880d681SAndroid Build Coastguard Worker   /// See ARM Reference Manual A6.3.2.
getT2SOImmValRotateVal(unsigned V)298*9880d681SAndroid Build Coastguard Worker   static inline int getT2SOImmValRotateVal(unsigned V) {
299*9880d681SAndroid Build Coastguard Worker     unsigned RotAmt = countLeadingZeros(V);
300*9880d681SAndroid Build Coastguard Worker     if (RotAmt >= 24)
301*9880d681SAndroid Build Coastguard Worker       return -1;
302*9880d681SAndroid Build Coastguard Worker 
303*9880d681SAndroid Build Coastguard Worker     // If 'Arg' can be handled with a single shifter_op return the value.
304*9880d681SAndroid Build Coastguard Worker     if ((rotr32(0xff000000U, RotAmt) & V) == V)
305*9880d681SAndroid Build Coastguard Worker       return (rotr32(V, 24 - RotAmt) & 0x7f) | ((RotAmt + 8) << 7);
306*9880d681SAndroid Build Coastguard Worker 
307*9880d681SAndroid Build Coastguard Worker     return -1;
308*9880d681SAndroid Build Coastguard Worker   }
309*9880d681SAndroid Build Coastguard Worker 
310*9880d681SAndroid Build Coastguard Worker   /// getT2SOImmVal - Given a 32-bit immediate, if it is something that can fit
311*9880d681SAndroid Build Coastguard Worker   /// into a Thumb-2 shifter_operand immediate operand, return the 12-bit
312*9880d681SAndroid Build Coastguard Worker   /// encoding for it.  If not, return -1.
313*9880d681SAndroid Build Coastguard Worker   /// See ARM Reference Manual A6.3.2.
getT2SOImmVal(unsigned Arg)314*9880d681SAndroid Build Coastguard Worker   static inline int getT2SOImmVal(unsigned Arg) {
315*9880d681SAndroid Build Coastguard Worker     // If 'Arg' is an 8-bit splat, then get the encoded value.
316*9880d681SAndroid Build Coastguard Worker     int Splat = getT2SOImmValSplatVal(Arg);
317*9880d681SAndroid Build Coastguard Worker     if (Splat != -1)
318*9880d681SAndroid Build Coastguard Worker       return Splat;
319*9880d681SAndroid Build Coastguard Worker 
320*9880d681SAndroid Build Coastguard Worker     // If 'Arg' can be handled with a single shifter_op return the value.
321*9880d681SAndroid Build Coastguard Worker     int Rot = getT2SOImmValRotateVal(Arg);
322*9880d681SAndroid Build Coastguard Worker     if (Rot != -1)
323*9880d681SAndroid Build Coastguard Worker       return Rot;
324*9880d681SAndroid Build Coastguard Worker 
325*9880d681SAndroid Build Coastguard Worker     return -1;
326*9880d681SAndroid Build Coastguard Worker   }
327*9880d681SAndroid Build Coastguard Worker 
getT2SOImmValRotate(unsigned V)328*9880d681SAndroid Build Coastguard Worker   static inline unsigned getT2SOImmValRotate(unsigned V) {
329*9880d681SAndroid Build Coastguard Worker     if ((V & ~255U) == 0) return 0;
330*9880d681SAndroid Build Coastguard Worker     // Use CTZ to compute the rotate amount.
331*9880d681SAndroid Build Coastguard Worker     unsigned RotAmt = countTrailingZeros(V);
332*9880d681SAndroid Build Coastguard Worker     return (32 - RotAmt) & 31;
333*9880d681SAndroid Build Coastguard Worker   }
334*9880d681SAndroid Build Coastguard Worker 
isT2SOImmTwoPartVal(unsigned Imm)335*9880d681SAndroid Build Coastguard Worker   static inline bool isT2SOImmTwoPartVal (unsigned Imm) {
336*9880d681SAndroid Build Coastguard Worker     unsigned V = Imm;
337*9880d681SAndroid Build Coastguard Worker     // Passing values can be any combination of splat values and shifter
338*9880d681SAndroid Build Coastguard Worker     // values. If this can be handled with a single shifter or splat, bail
339*9880d681SAndroid Build Coastguard Worker     // out. Those should be handled directly, not with a two-part val.
340*9880d681SAndroid Build Coastguard Worker     if (getT2SOImmValSplatVal(V) != -1)
341*9880d681SAndroid Build Coastguard Worker       return false;
342*9880d681SAndroid Build Coastguard Worker     V = rotr32 (~255U, getT2SOImmValRotate(V)) & V;
343*9880d681SAndroid Build Coastguard Worker     if (V == 0)
344*9880d681SAndroid Build Coastguard Worker       return false;
345*9880d681SAndroid Build Coastguard Worker 
346*9880d681SAndroid Build Coastguard Worker     // If this can be handled as an immediate, accept.
347*9880d681SAndroid Build Coastguard Worker     if (getT2SOImmVal(V) != -1) return true;
348*9880d681SAndroid Build Coastguard Worker 
349*9880d681SAndroid Build Coastguard Worker     // Likewise, try masking out a splat value first.
350*9880d681SAndroid Build Coastguard Worker     V = Imm;
351*9880d681SAndroid Build Coastguard Worker     if (getT2SOImmValSplatVal(V & 0xff00ff00U) != -1)
352*9880d681SAndroid Build Coastguard Worker       V &= ~0xff00ff00U;
353*9880d681SAndroid Build Coastguard Worker     else if (getT2SOImmValSplatVal(V & 0x00ff00ffU) != -1)
354*9880d681SAndroid Build Coastguard Worker       V &= ~0x00ff00ffU;
355*9880d681SAndroid Build Coastguard Worker     // If what's left can be handled as an immediate, accept.
356*9880d681SAndroid Build Coastguard Worker     if (getT2SOImmVal(V) != -1) return true;
357*9880d681SAndroid Build Coastguard Worker 
358*9880d681SAndroid Build Coastguard Worker     // Otherwise, do not accept.
359*9880d681SAndroid Build Coastguard Worker     return false;
360*9880d681SAndroid Build Coastguard Worker   }
361*9880d681SAndroid Build Coastguard Worker 
getT2SOImmTwoPartFirst(unsigned Imm)362*9880d681SAndroid Build Coastguard Worker   static inline unsigned getT2SOImmTwoPartFirst(unsigned Imm) {
363*9880d681SAndroid Build Coastguard Worker     assert (isT2SOImmTwoPartVal(Imm) &&
364*9880d681SAndroid Build Coastguard Worker             "Immedate cannot be encoded as two part immediate!");
365*9880d681SAndroid Build Coastguard Worker     // Try a shifter operand as one part
366*9880d681SAndroid Build Coastguard Worker     unsigned V = rotr32 (~255, getT2SOImmValRotate(Imm)) & Imm;
367*9880d681SAndroid Build Coastguard Worker     // If the rest is encodable as an immediate, then return it.
368*9880d681SAndroid Build Coastguard Worker     if (getT2SOImmVal(V) != -1) return V;
369*9880d681SAndroid Build Coastguard Worker 
370*9880d681SAndroid Build Coastguard Worker     // Try masking out a splat value first.
371*9880d681SAndroid Build Coastguard Worker     if (getT2SOImmValSplatVal(Imm & 0xff00ff00U) != -1)
372*9880d681SAndroid Build Coastguard Worker       return Imm & 0xff00ff00U;
373*9880d681SAndroid Build Coastguard Worker 
374*9880d681SAndroid Build Coastguard Worker     // The other splat is all that's left as an option.
375*9880d681SAndroid Build Coastguard Worker     assert (getT2SOImmValSplatVal(Imm & 0x00ff00ffU) != -1);
376*9880d681SAndroid Build Coastguard Worker     return Imm & 0x00ff00ffU;
377*9880d681SAndroid Build Coastguard Worker   }
378*9880d681SAndroid Build Coastguard Worker 
getT2SOImmTwoPartSecond(unsigned Imm)379*9880d681SAndroid Build Coastguard Worker   static inline unsigned getT2SOImmTwoPartSecond(unsigned Imm) {
380*9880d681SAndroid Build Coastguard Worker     // Mask out the first hunk
381*9880d681SAndroid Build Coastguard Worker     Imm ^= getT2SOImmTwoPartFirst(Imm);
382*9880d681SAndroid Build Coastguard Worker     // Return what's left
383*9880d681SAndroid Build Coastguard Worker     assert (getT2SOImmVal(Imm) != -1 &&
384*9880d681SAndroid Build Coastguard Worker             "Unable to encode second part of T2 two part SO immediate");
385*9880d681SAndroid Build Coastguard Worker     return Imm;
386*9880d681SAndroid Build Coastguard Worker   }
387*9880d681SAndroid Build Coastguard Worker 
388*9880d681SAndroid Build Coastguard Worker 
389*9880d681SAndroid Build Coastguard Worker   //===--------------------------------------------------------------------===//
390*9880d681SAndroid Build Coastguard Worker   // Addressing Mode #2
391*9880d681SAndroid Build Coastguard Worker   //===--------------------------------------------------------------------===//
392*9880d681SAndroid Build Coastguard Worker   //
393*9880d681SAndroid Build Coastguard Worker   // This is used for most simple load/store instructions.
394*9880d681SAndroid Build Coastguard Worker   //
395*9880d681SAndroid Build Coastguard Worker   // addrmode2 := reg +/- reg shop imm
396*9880d681SAndroid Build Coastguard Worker   // addrmode2 := reg +/- imm12
397*9880d681SAndroid Build Coastguard Worker   //
398*9880d681SAndroid Build Coastguard Worker   // The first operand is always a Reg.  The second operand is a reg if in
399*9880d681SAndroid Build Coastguard Worker   // reg/reg form, otherwise it's reg#0.  The third field encodes the operation
400*9880d681SAndroid Build Coastguard Worker   // in bit 12, the immediate in bits 0-11, and the shift op in 13-15. The
401*9880d681SAndroid Build Coastguard Worker   // fourth operand 16-17 encodes the index mode.
402*9880d681SAndroid Build Coastguard Worker   //
403*9880d681SAndroid Build Coastguard Worker   // If this addressing mode is a frame index (before prolog/epilog insertion
404*9880d681SAndroid Build Coastguard Worker   // and code rewriting), this operand will have the form:  FI#, reg0, <offs>
405*9880d681SAndroid Build Coastguard Worker   // with no shift amount for the frame offset.
406*9880d681SAndroid Build Coastguard Worker   //
407*9880d681SAndroid Build Coastguard Worker   static inline unsigned getAM2Opc(AddrOpc Opc, unsigned Imm12, ShiftOpc SO,
408*9880d681SAndroid Build Coastguard Worker                                    unsigned IdxMode = 0) {
409*9880d681SAndroid Build Coastguard Worker     assert(Imm12 < (1 << 12) && "Imm too large!");
410*9880d681SAndroid Build Coastguard Worker     bool isSub = Opc == sub;
411*9880d681SAndroid Build Coastguard Worker     return Imm12 | ((int)isSub << 12) | (SO << 13) | (IdxMode << 16) ;
412*9880d681SAndroid Build Coastguard Worker   }
getAM2Offset(unsigned AM2Opc)413*9880d681SAndroid Build Coastguard Worker   static inline unsigned getAM2Offset(unsigned AM2Opc) {
414*9880d681SAndroid Build Coastguard Worker     return AM2Opc & ((1 << 12)-1);
415*9880d681SAndroid Build Coastguard Worker   }
getAM2Op(unsigned AM2Opc)416*9880d681SAndroid Build Coastguard Worker   static inline AddrOpc getAM2Op(unsigned AM2Opc) {
417*9880d681SAndroid Build Coastguard Worker     return ((AM2Opc >> 12) & 1) ? sub : add;
418*9880d681SAndroid Build Coastguard Worker   }
getAM2ShiftOpc(unsigned AM2Opc)419*9880d681SAndroid Build Coastguard Worker   static inline ShiftOpc getAM2ShiftOpc(unsigned AM2Opc) {
420*9880d681SAndroid Build Coastguard Worker     return (ShiftOpc)((AM2Opc >> 13) & 7);
421*9880d681SAndroid Build Coastguard Worker   }
getAM2IdxMode(unsigned AM2Opc)422*9880d681SAndroid Build Coastguard Worker   static inline unsigned getAM2IdxMode(unsigned AM2Opc) {
423*9880d681SAndroid Build Coastguard Worker     return (AM2Opc >> 16);
424*9880d681SAndroid Build Coastguard Worker   }
425*9880d681SAndroid Build Coastguard Worker 
426*9880d681SAndroid Build Coastguard Worker 
427*9880d681SAndroid Build Coastguard Worker   //===--------------------------------------------------------------------===//
428*9880d681SAndroid Build Coastguard Worker   // Addressing Mode #3
429*9880d681SAndroid Build Coastguard Worker   //===--------------------------------------------------------------------===//
430*9880d681SAndroid Build Coastguard Worker   //
431*9880d681SAndroid Build Coastguard Worker   // This is used for sign-extending loads, and load/store-pair instructions.
432*9880d681SAndroid Build Coastguard Worker   //
433*9880d681SAndroid Build Coastguard Worker   // addrmode3 := reg +/- reg
434*9880d681SAndroid Build Coastguard Worker   // addrmode3 := reg +/- imm8
435*9880d681SAndroid Build Coastguard Worker   //
436*9880d681SAndroid Build Coastguard Worker   // The first operand is always a Reg.  The second operand is a reg if in
437*9880d681SAndroid Build Coastguard Worker   // reg/reg form, otherwise it's reg#0.  The third field encodes the operation
438*9880d681SAndroid Build Coastguard Worker   // in bit 8, the immediate in bits 0-7. The fourth operand 9-10 encodes the
439*9880d681SAndroid Build Coastguard Worker   // index mode.
440*9880d681SAndroid Build Coastguard Worker 
441*9880d681SAndroid Build Coastguard Worker   /// getAM3Opc - This function encodes the addrmode3 opc field.
442*9880d681SAndroid Build Coastguard Worker   static inline unsigned getAM3Opc(AddrOpc Opc, unsigned char Offset,
443*9880d681SAndroid Build Coastguard Worker                                    unsigned IdxMode = 0) {
444*9880d681SAndroid Build Coastguard Worker     bool isSub = Opc == sub;
445*9880d681SAndroid Build Coastguard Worker     return ((int)isSub << 8) | Offset | (IdxMode << 9);
446*9880d681SAndroid Build Coastguard Worker   }
getAM3Offset(unsigned AM3Opc)447*9880d681SAndroid Build Coastguard Worker   static inline unsigned char getAM3Offset(unsigned AM3Opc) {
448*9880d681SAndroid Build Coastguard Worker     return AM3Opc & 0xFF;
449*9880d681SAndroid Build Coastguard Worker   }
getAM3Op(unsigned AM3Opc)450*9880d681SAndroid Build Coastguard Worker   static inline AddrOpc getAM3Op(unsigned AM3Opc) {
451*9880d681SAndroid Build Coastguard Worker     return ((AM3Opc >> 8) & 1) ? sub : add;
452*9880d681SAndroid Build Coastguard Worker   }
getAM3IdxMode(unsigned AM3Opc)453*9880d681SAndroid Build Coastguard Worker   static inline unsigned getAM3IdxMode(unsigned AM3Opc) {
454*9880d681SAndroid Build Coastguard Worker     return (AM3Opc >> 9);
455*9880d681SAndroid Build Coastguard Worker   }
456*9880d681SAndroid Build Coastguard Worker 
457*9880d681SAndroid Build Coastguard Worker   //===--------------------------------------------------------------------===//
458*9880d681SAndroid Build Coastguard Worker   // Addressing Mode #4
459*9880d681SAndroid Build Coastguard Worker   //===--------------------------------------------------------------------===//
460*9880d681SAndroid Build Coastguard Worker   //
461*9880d681SAndroid Build Coastguard Worker   // This is used for load / store multiple instructions.
462*9880d681SAndroid Build Coastguard Worker   //
463*9880d681SAndroid Build Coastguard Worker   // addrmode4 := reg, <mode>
464*9880d681SAndroid Build Coastguard Worker   //
465*9880d681SAndroid Build Coastguard Worker   // The four modes are:
466*9880d681SAndroid Build Coastguard Worker   //    IA - Increment after
467*9880d681SAndroid Build Coastguard Worker   //    IB - Increment before
468*9880d681SAndroid Build Coastguard Worker   //    DA - Decrement after
469*9880d681SAndroid Build Coastguard Worker   //    DB - Decrement before
470*9880d681SAndroid Build Coastguard Worker   // For VFP instructions, only the IA and DB modes are valid.
471*9880d681SAndroid Build Coastguard Worker 
getAM4SubMode(unsigned Mode)472*9880d681SAndroid Build Coastguard Worker   static inline AMSubMode getAM4SubMode(unsigned Mode) {
473*9880d681SAndroid Build Coastguard Worker     return (AMSubMode)(Mode & 0x7);
474*9880d681SAndroid Build Coastguard Worker   }
475*9880d681SAndroid Build Coastguard Worker 
getAM4ModeImm(AMSubMode SubMode)476*9880d681SAndroid Build Coastguard Worker   static inline unsigned getAM4ModeImm(AMSubMode SubMode) {
477*9880d681SAndroid Build Coastguard Worker     return (int)SubMode;
478*9880d681SAndroid Build Coastguard Worker   }
479*9880d681SAndroid Build Coastguard Worker 
480*9880d681SAndroid Build Coastguard Worker   //===--------------------------------------------------------------------===//
481*9880d681SAndroid Build Coastguard Worker   // Addressing Mode #5
482*9880d681SAndroid Build Coastguard Worker   //===--------------------------------------------------------------------===//
483*9880d681SAndroid Build Coastguard Worker   //
484*9880d681SAndroid Build Coastguard Worker   // This is used for coprocessor instructions, such as FP load/stores.
485*9880d681SAndroid Build Coastguard Worker   //
486*9880d681SAndroid Build Coastguard Worker   // addrmode5 := reg +/- imm8*4
487*9880d681SAndroid Build Coastguard Worker   //
488*9880d681SAndroid Build Coastguard Worker   // The first operand is always a Reg.  The second operand encodes the
489*9880d681SAndroid Build Coastguard Worker   // operation (add or subtract) in bit 8 and the immediate in bits 0-7.
490*9880d681SAndroid Build Coastguard Worker 
491*9880d681SAndroid Build Coastguard Worker   /// getAM5Opc - This function encodes the addrmode5 opc field.
getAM5Opc(AddrOpc Opc,unsigned char Offset)492*9880d681SAndroid Build Coastguard Worker   static inline unsigned getAM5Opc(AddrOpc Opc, unsigned char Offset) {
493*9880d681SAndroid Build Coastguard Worker     bool isSub = Opc == sub;
494*9880d681SAndroid Build Coastguard Worker     return ((int)isSub << 8) | Offset;
495*9880d681SAndroid Build Coastguard Worker   }
getAM5Offset(unsigned AM5Opc)496*9880d681SAndroid Build Coastguard Worker   static inline unsigned char getAM5Offset(unsigned AM5Opc) {
497*9880d681SAndroid Build Coastguard Worker     return AM5Opc & 0xFF;
498*9880d681SAndroid Build Coastguard Worker   }
getAM5Op(unsigned AM5Opc)499*9880d681SAndroid Build Coastguard Worker   static inline AddrOpc getAM5Op(unsigned AM5Opc) {
500*9880d681SAndroid Build Coastguard Worker     return ((AM5Opc >> 8) & 1) ? sub : add;
501*9880d681SAndroid Build Coastguard Worker   }
502*9880d681SAndroid Build Coastguard Worker 
503*9880d681SAndroid Build Coastguard Worker   //===--------------------------------------------------------------------===//
504*9880d681SAndroid Build Coastguard Worker   // Addressing Mode #5 FP16
505*9880d681SAndroid Build Coastguard Worker   //===--------------------------------------------------------------------===//
506*9880d681SAndroid Build Coastguard Worker   //
507*9880d681SAndroid Build Coastguard Worker   // This is used for coprocessor instructions, such as 16-bit FP load/stores.
508*9880d681SAndroid Build Coastguard Worker   //
509*9880d681SAndroid Build Coastguard Worker   // addrmode5fp16 := reg +/- imm8*2
510*9880d681SAndroid Build Coastguard Worker   //
511*9880d681SAndroid Build Coastguard Worker   // The first operand is always a Reg.  The second operand encodes the
512*9880d681SAndroid Build Coastguard Worker   // operation (add or subtract) in bit 8 and the immediate in bits 0-7.
513*9880d681SAndroid Build Coastguard Worker 
514*9880d681SAndroid Build Coastguard Worker   /// getAM5FP16Opc - This function encodes the addrmode5fp16 opc field.
getAM5FP16Opc(AddrOpc Opc,unsigned char Offset)515*9880d681SAndroid Build Coastguard Worker   static inline unsigned getAM5FP16Opc(AddrOpc Opc, unsigned char Offset) {
516*9880d681SAndroid Build Coastguard Worker     bool isSub = Opc == sub;
517*9880d681SAndroid Build Coastguard Worker     return ((int)isSub << 8) | Offset;
518*9880d681SAndroid Build Coastguard Worker   }
getAM5FP16Offset(unsigned AM5Opc)519*9880d681SAndroid Build Coastguard Worker   static inline unsigned char getAM5FP16Offset(unsigned AM5Opc) {
520*9880d681SAndroid Build Coastguard Worker     return AM5Opc & 0xFF;
521*9880d681SAndroid Build Coastguard Worker   }
getAM5FP16Op(unsigned AM5Opc)522*9880d681SAndroid Build Coastguard Worker   static inline AddrOpc getAM5FP16Op(unsigned AM5Opc) {
523*9880d681SAndroid Build Coastguard Worker     return ((AM5Opc >> 8) & 1) ? sub : add;
524*9880d681SAndroid Build Coastguard Worker   }
525*9880d681SAndroid Build Coastguard Worker 
526*9880d681SAndroid Build Coastguard Worker   //===--------------------------------------------------------------------===//
527*9880d681SAndroid Build Coastguard Worker   // Addressing Mode #6
528*9880d681SAndroid Build Coastguard Worker   //===--------------------------------------------------------------------===//
529*9880d681SAndroid Build Coastguard Worker   //
530*9880d681SAndroid Build Coastguard Worker   // This is used for NEON load / store instructions.
531*9880d681SAndroid Build Coastguard Worker   //
532*9880d681SAndroid Build Coastguard Worker   // addrmode6 := reg with optional alignment
533*9880d681SAndroid Build Coastguard Worker   //
534*9880d681SAndroid Build Coastguard Worker   // This is stored in two operands [regaddr, align].  The first is the
535*9880d681SAndroid Build Coastguard Worker   // address register.  The second operand is the value of the alignment
536*9880d681SAndroid Build Coastguard Worker   // specifier in bytes or zero if no explicit alignment.
537*9880d681SAndroid Build Coastguard Worker   // Valid alignments depend on the specific instruction.
538*9880d681SAndroid Build Coastguard Worker 
539*9880d681SAndroid Build Coastguard Worker   //===--------------------------------------------------------------------===//
540*9880d681SAndroid Build Coastguard Worker   // NEON Modified Immediates
541*9880d681SAndroid Build Coastguard Worker   //===--------------------------------------------------------------------===//
542*9880d681SAndroid Build Coastguard Worker   //
543*9880d681SAndroid Build Coastguard Worker   // Several NEON instructions (e.g., VMOV) take a "modified immediate"
544*9880d681SAndroid Build Coastguard Worker   // vector operand, where a small immediate encoded in the instruction
545*9880d681SAndroid Build Coastguard Worker   // specifies a full NEON vector value.  These modified immediates are
546*9880d681SAndroid Build Coastguard Worker   // represented here as encoded integers.  The low 8 bits hold the immediate
547*9880d681SAndroid Build Coastguard Worker   // value; bit 12 holds the "Op" field of the instruction, and bits 11-8 hold
548*9880d681SAndroid Build Coastguard Worker   // the "Cmode" field of the instruction.  The interfaces below treat the
549*9880d681SAndroid Build Coastguard Worker   // Op and Cmode values as a single 5-bit value.
550*9880d681SAndroid Build Coastguard Worker 
createNEONModImm(unsigned OpCmode,unsigned Val)551*9880d681SAndroid Build Coastguard Worker   static inline unsigned createNEONModImm(unsigned OpCmode, unsigned Val) {
552*9880d681SAndroid Build Coastguard Worker     return (OpCmode << 8) | Val;
553*9880d681SAndroid Build Coastguard Worker   }
getNEONModImmOpCmode(unsigned ModImm)554*9880d681SAndroid Build Coastguard Worker   static inline unsigned getNEONModImmOpCmode(unsigned ModImm) {
555*9880d681SAndroid Build Coastguard Worker     return (ModImm >> 8) & 0x1f;
556*9880d681SAndroid Build Coastguard Worker   }
getNEONModImmVal(unsigned ModImm)557*9880d681SAndroid Build Coastguard Worker   static inline unsigned getNEONModImmVal(unsigned ModImm) {
558*9880d681SAndroid Build Coastguard Worker     return ModImm & 0xff;
559*9880d681SAndroid Build Coastguard Worker   }
560*9880d681SAndroid Build Coastguard Worker 
561*9880d681SAndroid Build Coastguard Worker   /// decodeNEONModImm - Decode a NEON modified immediate value into the
562*9880d681SAndroid Build Coastguard Worker   /// element value and the element size in bits.  (If the element size is
563*9880d681SAndroid Build Coastguard Worker   /// smaller than the vector, it is splatted into all the elements.)
decodeNEONModImm(unsigned ModImm,unsigned & EltBits)564*9880d681SAndroid Build Coastguard Worker   static inline uint64_t decodeNEONModImm(unsigned ModImm, unsigned &EltBits) {
565*9880d681SAndroid Build Coastguard Worker     unsigned OpCmode = getNEONModImmOpCmode(ModImm);
566*9880d681SAndroid Build Coastguard Worker     unsigned Imm8 = getNEONModImmVal(ModImm);
567*9880d681SAndroid Build Coastguard Worker     uint64_t Val = 0;
568*9880d681SAndroid Build Coastguard Worker 
569*9880d681SAndroid Build Coastguard Worker     if (OpCmode == 0xe) {
570*9880d681SAndroid Build Coastguard Worker       // 8-bit vector elements
571*9880d681SAndroid Build Coastguard Worker       Val = Imm8;
572*9880d681SAndroid Build Coastguard Worker       EltBits = 8;
573*9880d681SAndroid Build Coastguard Worker     } else if ((OpCmode & 0xc) == 0x8) {
574*9880d681SAndroid Build Coastguard Worker       // 16-bit vector elements
575*9880d681SAndroid Build Coastguard Worker       unsigned ByteNum = (OpCmode & 0x6) >> 1;
576*9880d681SAndroid Build Coastguard Worker       Val = Imm8 << (8 * ByteNum);
577*9880d681SAndroid Build Coastguard Worker       EltBits = 16;
578*9880d681SAndroid Build Coastguard Worker     } else if ((OpCmode & 0x8) == 0) {
579*9880d681SAndroid Build Coastguard Worker       // 32-bit vector elements, zero with one byte set
580*9880d681SAndroid Build Coastguard Worker       unsigned ByteNum = (OpCmode & 0x6) >> 1;
581*9880d681SAndroid Build Coastguard Worker       Val = Imm8 << (8 * ByteNum);
582*9880d681SAndroid Build Coastguard Worker       EltBits = 32;
583*9880d681SAndroid Build Coastguard Worker     } else if ((OpCmode & 0xe) == 0xc) {
584*9880d681SAndroid Build Coastguard Worker       // 32-bit vector elements, one byte with low bits set
585*9880d681SAndroid Build Coastguard Worker       unsigned ByteNum = 1 + (OpCmode & 0x1);
586*9880d681SAndroid Build Coastguard Worker       Val = (Imm8 << (8 * ByteNum)) | (0xffff >> (8 * (2 - ByteNum)));
587*9880d681SAndroid Build Coastguard Worker       EltBits = 32;
588*9880d681SAndroid Build Coastguard Worker     } else if (OpCmode == 0x1e) {
589*9880d681SAndroid Build Coastguard Worker       // 64-bit vector elements
590*9880d681SAndroid Build Coastguard Worker       for (unsigned ByteNum = 0; ByteNum < 8; ++ByteNum) {
591*9880d681SAndroid Build Coastguard Worker         if ((ModImm >> ByteNum) & 1)
592*9880d681SAndroid Build Coastguard Worker           Val |= (uint64_t)0xff << (8 * ByteNum);
593*9880d681SAndroid Build Coastguard Worker       }
594*9880d681SAndroid Build Coastguard Worker       EltBits = 64;
595*9880d681SAndroid Build Coastguard Worker     } else {
596*9880d681SAndroid Build Coastguard Worker       llvm_unreachable("Unsupported NEON immediate");
597*9880d681SAndroid Build Coastguard Worker     }
598*9880d681SAndroid Build Coastguard Worker     return Val;
599*9880d681SAndroid Build Coastguard Worker   }
600*9880d681SAndroid Build Coastguard Worker 
601*9880d681SAndroid Build Coastguard Worker   // Generic validation for single-byte immediate (0X00, 00X0, etc).
isNEONBytesplat(unsigned Value,unsigned Size)602*9880d681SAndroid Build Coastguard Worker   static inline bool isNEONBytesplat(unsigned Value, unsigned Size) {
603*9880d681SAndroid Build Coastguard Worker     assert(Size >= 1 && Size <= 4 && "Invalid size");
604*9880d681SAndroid Build Coastguard Worker     unsigned count = 0;
605*9880d681SAndroid Build Coastguard Worker     for (unsigned i = 0; i < Size; ++i) {
606*9880d681SAndroid Build Coastguard Worker       if (Value & 0xff) count++;
607*9880d681SAndroid Build Coastguard Worker       Value >>= 8;
608*9880d681SAndroid Build Coastguard Worker     }
609*9880d681SAndroid Build Coastguard Worker     return count == 1;
610*9880d681SAndroid Build Coastguard Worker   }
611*9880d681SAndroid Build Coastguard Worker 
612*9880d681SAndroid Build Coastguard Worker   /// Checks if Value is a correct immediate for instructions like VBIC/VORR.
isNEONi16splat(unsigned Value)613*9880d681SAndroid Build Coastguard Worker   static inline bool isNEONi16splat(unsigned Value) {
614*9880d681SAndroid Build Coastguard Worker     if (Value > 0xffff)
615*9880d681SAndroid Build Coastguard Worker       return false;
616*9880d681SAndroid Build Coastguard Worker     // i16 value with set bits only in one byte X0 or 0X.
617*9880d681SAndroid Build Coastguard Worker     return Value == 0 || isNEONBytesplat(Value, 2);
618*9880d681SAndroid Build Coastguard Worker   }
619*9880d681SAndroid Build Coastguard Worker 
620*9880d681SAndroid Build Coastguard Worker   // Encode NEON 16 bits Splat immediate for instructions like VBIC/VORR
encodeNEONi16splat(unsigned Value)621*9880d681SAndroid Build Coastguard Worker   static inline unsigned encodeNEONi16splat(unsigned Value) {
622*9880d681SAndroid Build Coastguard Worker     assert(isNEONi16splat(Value) && "Invalid NEON splat value");
623*9880d681SAndroid Build Coastguard Worker     if (Value >= 0x100)
624*9880d681SAndroid Build Coastguard Worker       Value = (Value >> 8) | 0xa00;
625*9880d681SAndroid Build Coastguard Worker     else
626*9880d681SAndroid Build Coastguard Worker       Value |= 0x800;
627*9880d681SAndroid Build Coastguard Worker     return Value;
628*9880d681SAndroid Build Coastguard Worker   }
629*9880d681SAndroid Build Coastguard Worker 
630*9880d681SAndroid Build Coastguard Worker   /// Checks if Value is a correct immediate for instructions like VBIC/VORR.
isNEONi32splat(unsigned Value)631*9880d681SAndroid Build Coastguard Worker   static inline bool isNEONi32splat(unsigned Value) {
632*9880d681SAndroid Build Coastguard Worker     // i32 value with set bits only in one byte X000, 0X00, 00X0, or 000X.
633*9880d681SAndroid Build Coastguard Worker     return Value == 0 || isNEONBytesplat(Value, 4);
634*9880d681SAndroid Build Coastguard Worker   }
635*9880d681SAndroid Build Coastguard Worker 
636*9880d681SAndroid Build Coastguard Worker   /// Encode NEON 32 bits Splat immediate for instructions like VBIC/VORR.
encodeNEONi32splat(unsigned Value)637*9880d681SAndroid Build Coastguard Worker   static inline unsigned encodeNEONi32splat(unsigned Value) {
638*9880d681SAndroid Build Coastguard Worker     assert(isNEONi32splat(Value) && "Invalid NEON splat value");
639*9880d681SAndroid Build Coastguard Worker     if (Value >= 0x100 && Value <= 0xff00)
640*9880d681SAndroid Build Coastguard Worker       Value = (Value >> 8) | 0x200;
641*9880d681SAndroid Build Coastguard Worker     else if (Value > 0xffff && Value <= 0xff0000)
642*9880d681SAndroid Build Coastguard Worker       Value = (Value >> 16) | 0x400;
643*9880d681SAndroid Build Coastguard Worker     else if (Value > 0xffffff)
644*9880d681SAndroid Build Coastguard Worker       Value = (Value >> 24) | 0x600;
645*9880d681SAndroid Build Coastguard Worker     return Value;
646*9880d681SAndroid Build Coastguard Worker   }
647*9880d681SAndroid Build Coastguard Worker 
648*9880d681SAndroid Build Coastguard Worker   //===--------------------------------------------------------------------===//
649*9880d681SAndroid Build Coastguard Worker   // Floating-point Immediates
650*9880d681SAndroid Build Coastguard Worker   //
getFPImmFloat(unsigned Imm)651*9880d681SAndroid Build Coastguard Worker   static inline float getFPImmFloat(unsigned Imm) {
652*9880d681SAndroid Build Coastguard Worker     // We expect an 8-bit binary encoding of a floating-point number here.
653*9880d681SAndroid Build Coastguard Worker     union {
654*9880d681SAndroid Build Coastguard Worker       uint32_t I;
655*9880d681SAndroid Build Coastguard Worker       float F;
656*9880d681SAndroid Build Coastguard Worker     } FPUnion;
657*9880d681SAndroid Build Coastguard Worker 
658*9880d681SAndroid Build Coastguard Worker     uint8_t Sign = (Imm >> 7) & 0x1;
659*9880d681SAndroid Build Coastguard Worker     uint8_t Exp = (Imm >> 4) & 0x7;
660*9880d681SAndroid Build Coastguard Worker     uint8_t Mantissa = Imm & 0xf;
661*9880d681SAndroid Build Coastguard Worker 
662*9880d681SAndroid Build Coastguard Worker     //   8-bit FP    iEEEE Float Encoding
663*9880d681SAndroid Build Coastguard Worker     //   abcd efgh   aBbbbbbc defgh000 00000000 00000000
664*9880d681SAndroid Build Coastguard Worker     //
665*9880d681SAndroid Build Coastguard Worker     // where B = NOT(b);
666*9880d681SAndroid Build Coastguard Worker 
667*9880d681SAndroid Build Coastguard Worker     FPUnion.I = 0;
668*9880d681SAndroid Build Coastguard Worker     FPUnion.I |= Sign << 31;
669*9880d681SAndroid Build Coastguard Worker     FPUnion.I |= ((Exp & 0x4) != 0 ? 0 : 1) << 30;
670*9880d681SAndroid Build Coastguard Worker     FPUnion.I |= ((Exp & 0x4) != 0 ? 0x1f : 0) << 25;
671*9880d681SAndroid Build Coastguard Worker     FPUnion.I |= (Exp & 0x3) << 23;
672*9880d681SAndroid Build Coastguard Worker     FPUnion.I |= Mantissa << 19;
673*9880d681SAndroid Build Coastguard Worker     return FPUnion.F;
674*9880d681SAndroid Build Coastguard Worker   }
675*9880d681SAndroid Build Coastguard Worker 
676*9880d681SAndroid Build Coastguard Worker   /// getFP16Imm - Return an 8-bit floating-point version of the 16-bit
677*9880d681SAndroid Build Coastguard Worker   /// floating-point value. If the value cannot be represented as an 8-bit
678*9880d681SAndroid Build Coastguard Worker   /// floating-point value, then return -1.
getFP16Imm(const APInt & Imm)679*9880d681SAndroid Build Coastguard Worker   static inline int getFP16Imm(const APInt &Imm) {
680*9880d681SAndroid Build Coastguard Worker     uint32_t Sign = Imm.lshr(15).getZExtValue() & 1;
681*9880d681SAndroid Build Coastguard Worker     int32_t Exp = (Imm.lshr(10).getSExtValue() & 0x1f) - 15;  // -14 to 15
682*9880d681SAndroid Build Coastguard Worker     int64_t Mantissa = Imm.getZExtValue() & 0x3ff;  // 10 bits
683*9880d681SAndroid Build Coastguard Worker 
684*9880d681SAndroid Build Coastguard Worker     // We can handle 4 bits of mantissa.
685*9880d681SAndroid Build Coastguard Worker     // mantissa = (16+UInt(e:f:g:h))/16.
686*9880d681SAndroid Build Coastguard Worker     if (Mantissa & 0x3f)
687*9880d681SAndroid Build Coastguard Worker       return -1;
688*9880d681SAndroid Build Coastguard Worker     Mantissa >>= 6;
689*9880d681SAndroid Build Coastguard Worker 
690*9880d681SAndroid Build Coastguard Worker     // We can handle 3 bits of exponent: exp == UInt(NOT(b):c:d)-3
691*9880d681SAndroid Build Coastguard Worker     if (Exp < -3 || Exp > 4)
692*9880d681SAndroid Build Coastguard Worker       return -1;
693*9880d681SAndroid Build Coastguard Worker     Exp = ((Exp+3) & 0x7) ^ 4;
694*9880d681SAndroid Build Coastguard Worker 
695*9880d681SAndroid Build Coastguard Worker     return ((int)Sign << 7) | (Exp << 4) | Mantissa;
696*9880d681SAndroid Build Coastguard Worker   }
697*9880d681SAndroid Build Coastguard Worker 
getFP16Imm(const APFloat & FPImm)698*9880d681SAndroid Build Coastguard Worker   static inline int getFP16Imm(const APFloat &FPImm) {
699*9880d681SAndroid Build Coastguard Worker     return getFP16Imm(FPImm.bitcastToAPInt());
700*9880d681SAndroid Build Coastguard Worker   }
701*9880d681SAndroid Build Coastguard Worker 
702*9880d681SAndroid Build Coastguard Worker   /// getFP32Imm - Return an 8-bit floating-point version of the 32-bit
703*9880d681SAndroid Build Coastguard Worker   /// floating-point value. If the value cannot be represented as an 8-bit
704*9880d681SAndroid Build Coastguard Worker   /// floating-point value, then return -1.
getFP32Imm(const APInt & Imm)705*9880d681SAndroid Build Coastguard Worker   static inline int getFP32Imm(const APInt &Imm) {
706*9880d681SAndroid Build Coastguard Worker     uint32_t Sign = Imm.lshr(31).getZExtValue() & 1;
707*9880d681SAndroid Build Coastguard Worker     int32_t Exp = (Imm.lshr(23).getSExtValue() & 0xff) - 127;  // -126 to 127
708*9880d681SAndroid Build Coastguard Worker     int64_t Mantissa = Imm.getZExtValue() & 0x7fffff;  // 23 bits
709*9880d681SAndroid Build Coastguard Worker 
710*9880d681SAndroid Build Coastguard Worker     // We can handle 4 bits of mantissa.
711*9880d681SAndroid Build Coastguard Worker     // mantissa = (16+UInt(e:f:g:h))/16.
712*9880d681SAndroid Build Coastguard Worker     if (Mantissa & 0x7ffff)
713*9880d681SAndroid Build Coastguard Worker       return -1;
714*9880d681SAndroid Build Coastguard Worker     Mantissa >>= 19;
715*9880d681SAndroid Build Coastguard Worker     if ((Mantissa & 0xf) != Mantissa)
716*9880d681SAndroid Build Coastguard Worker       return -1;
717*9880d681SAndroid Build Coastguard Worker 
718*9880d681SAndroid Build Coastguard Worker     // We can handle 3 bits of exponent: exp == UInt(NOT(b):c:d)-3
719*9880d681SAndroid Build Coastguard Worker     if (Exp < -3 || Exp > 4)
720*9880d681SAndroid Build Coastguard Worker       return -1;
721*9880d681SAndroid Build Coastguard Worker     Exp = ((Exp+3) & 0x7) ^ 4;
722*9880d681SAndroid Build Coastguard Worker 
723*9880d681SAndroid Build Coastguard Worker     return ((int)Sign << 7) | (Exp << 4) | Mantissa;
724*9880d681SAndroid Build Coastguard Worker   }
725*9880d681SAndroid Build Coastguard Worker 
getFP32Imm(const APFloat & FPImm)726*9880d681SAndroid Build Coastguard Worker   static inline int getFP32Imm(const APFloat &FPImm) {
727*9880d681SAndroid Build Coastguard Worker     return getFP32Imm(FPImm.bitcastToAPInt());
728*9880d681SAndroid Build Coastguard Worker   }
729*9880d681SAndroid Build Coastguard Worker 
730*9880d681SAndroid Build Coastguard Worker   /// getFP64Imm - Return an 8-bit floating-point version of the 64-bit
731*9880d681SAndroid Build Coastguard Worker   /// floating-point value. If the value cannot be represented as an 8-bit
732*9880d681SAndroid Build Coastguard Worker   /// floating-point value, then return -1.
getFP64Imm(const APInt & Imm)733*9880d681SAndroid Build Coastguard Worker   static inline int getFP64Imm(const APInt &Imm) {
734*9880d681SAndroid Build Coastguard Worker     uint64_t Sign = Imm.lshr(63).getZExtValue() & 1;
735*9880d681SAndroid Build Coastguard Worker     int64_t Exp = (Imm.lshr(52).getSExtValue() & 0x7ff) - 1023; // -1022 to 1023
736*9880d681SAndroid Build Coastguard Worker     uint64_t Mantissa = Imm.getZExtValue() & 0xfffffffffffffULL;
737*9880d681SAndroid Build Coastguard Worker 
738*9880d681SAndroid Build Coastguard Worker     // We can handle 4 bits of mantissa.
739*9880d681SAndroid Build Coastguard Worker     // mantissa = (16+UInt(e:f:g:h))/16.
740*9880d681SAndroid Build Coastguard Worker     if (Mantissa & 0xffffffffffffULL)
741*9880d681SAndroid Build Coastguard Worker       return -1;
742*9880d681SAndroid Build Coastguard Worker     Mantissa >>= 48;
743*9880d681SAndroid Build Coastguard Worker     if ((Mantissa & 0xf) != Mantissa)
744*9880d681SAndroid Build Coastguard Worker       return -1;
745*9880d681SAndroid Build Coastguard Worker 
746*9880d681SAndroid Build Coastguard Worker     // We can handle 3 bits of exponent: exp == UInt(NOT(b):c:d)-3
747*9880d681SAndroid Build Coastguard Worker     if (Exp < -3 || Exp > 4)
748*9880d681SAndroid Build Coastguard Worker       return -1;
749*9880d681SAndroid Build Coastguard Worker     Exp = ((Exp+3) & 0x7) ^ 4;
750*9880d681SAndroid Build Coastguard Worker 
751*9880d681SAndroid Build Coastguard Worker     return ((int)Sign << 7) | (Exp << 4) | Mantissa;
752*9880d681SAndroid Build Coastguard Worker   }
753*9880d681SAndroid Build Coastguard Worker 
getFP64Imm(const APFloat & FPImm)754*9880d681SAndroid Build Coastguard Worker   static inline int getFP64Imm(const APFloat &FPImm) {
755*9880d681SAndroid Build Coastguard Worker     return getFP64Imm(FPImm.bitcastToAPInt());
756*9880d681SAndroid Build Coastguard Worker   }
757*9880d681SAndroid Build Coastguard Worker 
758*9880d681SAndroid Build Coastguard Worker } // end namespace ARM_AM
759*9880d681SAndroid Build Coastguard Worker } // end namespace llvm
760*9880d681SAndroid Build Coastguard Worker 
761*9880d681SAndroid Build Coastguard Worker #endif
762*9880d681SAndroid Build Coastguard Worker 
763