1235633Sdim//===-- ARMAddressingModes.h - ARM Addressing Modes -------------*- C++ -*-===//
2226584Sdim//
3226584Sdim//                     The LLVM Compiler Infrastructure
4226584Sdim//
5226584Sdim// This file is distributed under the University of Illinois Open Source
6226584Sdim// License. See LICENSE.TXT for details.
7226584Sdim//
8226584Sdim//===----------------------------------------------------------------------===//
9226584Sdim//
10226584Sdim// This file contains the ARM addressing mode implementation stuff.
11226584Sdim//
12226584Sdim//===----------------------------------------------------------------------===//
13226584Sdim
14226584Sdim#ifndef LLVM_TARGET_ARM_ARMADDRESSINGMODES_H
15226584Sdim#define LLVM_TARGET_ARM_ARMADDRESSINGMODES_H
16226584Sdim
17226584Sdim#include "llvm/ADT/APFloat.h"
18226584Sdim#include "llvm/ADT/APInt.h"
19235633Sdim#include "llvm/Support/ErrorHandling.h"
20226584Sdim#include "llvm/Support/MathExtras.h"
21226584Sdim#include <cassert>
22226584Sdim
23226584Sdimnamespace llvm {
24226584Sdim
25226584Sdim/// ARM_AM - ARM Addressing Mode Stuff
26226584Sdimnamespace ARM_AM {
27226584Sdim  enum ShiftOpc {
28226584Sdim    no_shift = 0,
29226584Sdim    asr,
30226584Sdim    lsl,
31226584Sdim    lsr,
32226584Sdim    ror,
33226584Sdim    rrx
34226584Sdim  };
35226584Sdim
36226584Sdim  enum AddrOpc {
37226584Sdim    sub = 0,
38226584Sdim    add
39226584Sdim  };
40226584Sdim
41226584Sdim  static inline const char *getAddrOpcStr(AddrOpc Op) {
42226584Sdim    return Op == sub ? "-" : "";
43226584Sdim  }
44226584Sdim
45226584Sdim  static inline const char *getShiftOpcStr(ShiftOpc Op) {
46226584Sdim    switch (Op) {
47235633Sdim    default: llvm_unreachable("Unknown shift opc!");
48226584Sdim    case ARM_AM::asr: return "asr";
49226584Sdim    case ARM_AM::lsl: return "lsl";
50226584Sdim    case ARM_AM::lsr: return "lsr";
51226584Sdim    case ARM_AM::ror: return "ror";
52226584Sdim    case ARM_AM::rrx: return "rrx";
53226584Sdim    }
54226584Sdim  }
55226584Sdim
56226584Sdim  static inline unsigned getShiftOpcEncoding(ShiftOpc Op) {
57226584Sdim    switch (Op) {
58235633Sdim    default: llvm_unreachable("Unknown shift opc!");
59226584Sdim    case ARM_AM::asr: return 2;
60226584Sdim    case ARM_AM::lsl: return 0;
61226584Sdim    case ARM_AM::lsr: return 1;
62226584Sdim    case ARM_AM::ror: return 3;
63226584Sdim    }
64226584Sdim  }
65226584Sdim
66226584Sdim  enum AMSubMode {
67226584Sdim    bad_am_submode = 0,
68226584Sdim    ia,
69226584Sdim    ib,
70226584Sdim    da,
71226584Sdim    db
72226584Sdim  };
73226584Sdim
74226584Sdim  static inline const char *getAMSubModeStr(AMSubMode Mode) {
75226584Sdim    switch (Mode) {
76235633Sdim    default: llvm_unreachable("Unknown addressing sub-mode!");
77226584Sdim    case ARM_AM::ia: return "ia";
78226584Sdim    case ARM_AM::ib: return "ib";
79226584Sdim    case ARM_AM::da: return "da";
80226584Sdim    case ARM_AM::db: return "db";
81226584Sdim    }
82226584Sdim  }
83226584Sdim
84226584Sdim  /// rotr32 - Rotate a 32-bit unsigned value right by a specified # bits.
85226584Sdim  ///
86226584Sdim  static inline unsigned rotr32(unsigned Val, unsigned Amt) {
87226584Sdim    assert(Amt < 32 && "Invalid rotate amount");
88226584Sdim    return (Val >> Amt) | (Val << ((32-Amt)&31));
89226584Sdim  }
90226584Sdim
91226584Sdim  /// rotl32 - Rotate a 32-bit unsigned value left by a specified # bits.
92226584Sdim  ///
93226584Sdim  static inline unsigned rotl32(unsigned Val, unsigned Amt) {
94226584Sdim    assert(Amt < 32 && "Invalid rotate amount");
95226584Sdim    return (Val << Amt) | (Val >> ((32-Amt)&31));
96226584Sdim  }
97226584Sdim
98226584Sdim  //===--------------------------------------------------------------------===//
99226584Sdim  // Addressing Mode #1: shift_operand with registers
100226584Sdim  //===--------------------------------------------------------------------===//
101226584Sdim  //
102226584Sdim  // This 'addressing mode' is used for arithmetic instructions.  It can
103226584Sdim  // represent things like:
104226584Sdim  //   reg
105226584Sdim  //   reg [asr|lsl|lsr|ror|rrx] reg
106226584Sdim  //   reg [asr|lsl|lsr|ror|rrx] imm
107226584Sdim  //
108226584Sdim  // This is stored three operands [rega, regb, opc].  The first is the base
109226584Sdim  // reg, the second is the shift amount (or reg0 if not present or imm).  The
110226584Sdim  // third operand encodes the shift opcode and the imm if a reg isn't present.
111226584Sdim  //
112226584Sdim  static inline unsigned getSORegOpc(ShiftOpc ShOp, unsigned Imm) {
113226584Sdim    return ShOp | (Imm << 3);
114226584Sdim  }
115226584Sdim  static inline unsigned getSORegOffset(unsigned Op) {
116226584Sdim    return Op >> 3;
117226584Sdim  }
118226584Sdim  static inline ShiftOpc getSORegShOp(unsigned Op) {
119226584Sdim    return (ShiftOpc)(Op & 7);
120226584Sdim  }
121226584Sdim
122226584Sdim  /// getSOImmValImm - Given an encoded imm field for the reg/imm form, return
123226584Sdim  /// the 8-bit imm value.
124226584Sdim  static inline unsigned getSOImmValImm(unsigned Imm) {
125226584Sdim    return Imm & 0xFF;
126226584Sdim  }
127226584Sdim  /// getSOImmValRot - Given an encoded imm field for the reg/imm form, return
128226584Sdim  /// the rotate amount.
129226584Sdim  static inline unsigned getSOImmValRot(unsigned Imm) {
130226584Sdim    return (Imm >> 8) * 2;
131226584Sdim  }
132226584Sdim
133226584Sdim  /// getSOImmValRotate - Try to handle Imm with an immediate shifter operand,
134226584Sdim  /// computing the rotate amount to use.  If this immediate value cannot be
135226584Sdim  /// handled with a single shifter-op, determine a good rotate amount that will
136226584Sdim  /// take a maximal chunk of bits out of the immediate.
137226584Sdim  static inline unsigned getSOImmValRotate(unsigned Imm) {
138226584Sdim    // 8-bit (or less) immediates are trivially shifter_operands with a rotate
139226584Sdim    // of zero.
140226584Sdim    if ((Imm & ~255U) == 0) return 0;
141226584Sdim
142226584Sdim    // Use CTZ to compute the rotate amount.
143263509Sdim    unsigned TZ = countTrailingZeros(Imm);
144226584Sdim
145226584Sdim    // Rotate amount must be even.  Something like 0x200 must be rotated 8 bits,
146226584Sdim    // not 9.
147226584Sdim    unsigned RotAmt = TZ & ~1;
148226584Sdim
149226584Sdim    // If we can handle this spread, return it.
150226584Sdim    if ((rotr32(Imm, RotAmt) & ~255U) == 0)
151226584Sdim      return (32-RotAmt)&31;  // HW rotates right, not left.
152226584Sdim
153226584Sdim    // For values like 0xF000000F, we should ignore the low 6 bits, then
154226584Sdim    // retry the hunt.
155226584Sdim    if (Imm & 63U) {
156263509Sdim      unsigned TZ2 = countTrailingZeros(Imm & ~63U);
157226584Sdim      unsigned RotAmt2 = TZ2 & ~1;
158226584Sdim      if ((rotr32(Imm, RotAmt2) & ~255U) == 0)
159226584Sdim        return (32-RotAmt2)&31;  // HW rotates right, not left.
160226584Sdim    }
161226584Sdim
162226584Sdim    // Otherwise, we have no way to cover this span of bits with a single
163226584Sdim    // shifter_op immediate.  Return a chunk of bits that will be useful to
164226584Sdim    // handle.
165226584Sdim    return (32-RotAmt)&31;  // HW rotates right, not left.
166226584Sdim  }
167226584Sdim
168226584Sdim  /// getSOImmVal - Given a 32-bit immediate, if it is something that can fit
169226584Sdim  /// into an shifter_operand immediate operand, return the 12-bit encoding for
170226584Sdim  /// it.  If not, return -1.
171226584Sdim  static inline int getSOImmVal(unsigned Arg) {
172226584Sdim    // 8-bit (or less) immediates are trivially shifter_operands with a rotate
173226584Sdim    // of zero.
174226584Sdim    if ((Arg & ~255U) == 0) return Arg;
175226584Sdim
176226584Sdim    unsigned RotAmt = getSOImmValRotate(Arg);
177226584Sdim
178226584Sdim    // If this cannot be handled with a single shifter_op, bail out.
179226584Sdim    if (rotr32(~255U, RotAmt) & Arg)
180226584Sdim      return -1;
181226584Sdim
182226584Sdim    // Encode this correctly.
183226584Sdim    return rotl32(Arg, RotAmt) | ((RotAmt>>1) << 8);
184226584Sdim  }
185226584Sdim
186226584Sdim  /// isSOImmTwoPartVal - Return true if the specified value can be obtained by
187226584Sdim  /// or'ing together two SOImmVal's.
188226584Sdim  static inline bool isSOImmTwoPartVal(unsigned V) {
189226584Sdim    // If this can be handled with a single shifter_op, bail out.
190226584Sdim    V = rotr32(~255U, getSOImmValRotate(V)) & V;
191226584Sdim    if (V == 0)
192226584Sdim      return false;
193226584Sdim
194226584Sdim    // If this can be handled with two shifter_op's, accept.
195226584Sdim    V = rotr32(~255U, getSOImmValRotate(V)) & V;
196226584Sdim    return V == 0;
197226584Sdim  }
198226584Sdim
199226584Sdim  /// getSOImmTwoPartFirst - If V is a value that satisfies isSOImmTwoPartVal,
200226584Sdim  /// return the first chunk of it.
201226584Sdim  static inline unsigned getSOImmTwoPartFirst(unsigned V) {
202226584Sdim    return rotr32(255U, getSOImmValRotate(V)) & V;
203226584Sdim  }
204226584Sdim
205226584Sdim  /// getSOImmTwoPartSecond - If V is a value that satisfies isSOImmTwoPartVal,
206226584Sdim  /// return the second chunk of it.
207226584Sdim  static inline unsigned getSOImmTwoPartSecond(unsigned V) {
208226584Sdim    // Mask out the first hunk.
209226584Sdim    V = rotr32(~255U, getSOImmValRotate(V)) & V;
210226584Sdim
211226584Sdim    // Take what's left.
212226584Sdim    assert(V == (rotr32(255U, getSOImmValRotate(V)) & V));
213226584Sdim    return V;
214226584Sdim  }
215226584Sdim
216226584Sdim  /// getThumbImmValShift - Try to handle Imm with a 8-bit immediate followed
217226584Sdim  /// by a left shift. Returns the shift amount to use.
218226584Sdim  static inline unsigned getThumbImmValShift(unsigned Imm) {
219226584Sdim    // 8-bit (or less) immediates are trivially immediate operand with a shift
220226584Sdim    // of zero.
221226584Sdim    if ((Imm & ~255U) == 0) return 0;
222226584Sdim
223226584Sdim    // Use CTZ to compute the shift amount.
224263509Sdim    return countTrailingZeros(Imm);
225226584Sdim  }
226226584Sdim
227226584Sdim  /// isThumbImmShiftedVal - Return true if the specified value can be obtained
228226584Sdim  /// by left shifting a 8-bit immediate.
229226584Sdim  static inline bool isThumbImmShiftedVal(unsigned V) {
230226584Sdim    // If this can be handled with
231226584Sdim    V = (~255U << getThumbImmValShift(V)) & V;
232226584Sdim    return V == 0;
233226584Sdim  }
234226584Sdim
235226584Sdim  /// getThumbImm16ValShift - Try to handle Imm with a 16-bit immediate followed
236226584Sdim  /// by a left shift. Returns the shift amount to use.
237226584Sdim  static inline unsigned getThumbImm16ValShift(unsigned Imm) {
238226584Sdim    // 16-bit (or less) immediates are trivially immediate operand with a shift
239226584Sdim    // of zero.
240226584Sdim    if ((Imm & ~65535U) == 0) return 0;
241226584Sdim
242226584Sdim    // Use CTZ to compute the shift amount.
243263509Sdim    return countTrailingZeros(Imm);
244226584Sdim  }
245226584Sdim
246226584Sdim  /// isThumbImm16ShiftedVal - Return true if the specified value can be
247226584Sdim  /// obtained by left shifting a 16-bit immediate.
248226584Sdim  static inline bool isThumbImm16ShiftedVal(unsigned V) {
249226584Sdim    // If this can be handled with
250226584Sdim    V = (~65535U << getThumbImm16ValShift(V)) & V;
251226584Sdim    return V == 0;
252226584Sdim  }
253226584Sdim
254226584Sdim  /// getThumbImmNonShiftedVal - If V is a value that satisfies
255226584Sdim  /// isThumbImmShiftedVal, return the non-shiftd value.
256226584Sdim  static inline unsigned getThumbImmNonShiftedVal(unsigned V) {
257226584Sdim    return V >> getThumbImmValShift(V);
258226584Sdim  }
259226584Sdim
260226584Sdim
261226584Sdim  /// getT2SOImmValSplat - Return the 12-bit encoded representation
262226584Sdim  /// if the specified value can be obtained by splatting the low 8 bits
263226584Sdim  /// into every other byte or every byte of a 32-bit value. i.e.,
264226584Sdim  ///     00000000 00000000 00000000 abcdefgh    control = 0
265226584Sdim  ///     00000000 abcdefgh 00000000 abcdefgh    control = 1
266226584Sdim  ///     abcdefgh 00000000 abcdefgh 00000000    control = 2
267226584Sdim  ///     abcdefgh abcdefgh abcdefgh abcdefgh    control = 3
268226584Sdim  /// Return -1 if none of the above apply.
269226584Sdim  /// See ARM Reference Manual A6.3.2.
270226584Sdim  static inline int getT2SOImmValSplatVal(unsigned V) {
271226584Sdim    unsigned u, Vs, Imm;
272226584Sdim    // control = 0
273226584Sdim    if ((V & 0xffffff00) == 0)
274226584Sdim      return V;
275226584Sdim
276226584Sdim    // If the value is zeroes in the first byte, just shift those off
277226584Sdim    Vs = ((V & 0xff) == 0) ? V >> 8 : V;
278226584Sdim    // Any passing value only has 8 bits of payload, splatted across the word
279226584Sdim    Imm = Vs & 0xff;
280226584Sdim    // Likewise, any passing values have the payload splatted into the 3rd byte
281226584Sdim    u = Imm | (Imm << 16);
282226584Sdim
283226584Sdim    // control = 1 or 2
284226584Sdim    if (Vs == u)
285226584Sdim      return (((Vs == V) ? 1 : 2) << 8) | Imm;
286226584Sdim
287226584Sdim    // control = 3
288226584Sdim    if (Vs == (u | (u << 8)))
289226584Sdim      return (3 << 8) | Imm;
290226584Sdim
291226584Sdim    return -1;
292226584Sdim  }
293226584Sdim
294226584Sdim  /// getT2SOImmValRotateVal - Return the 12-bit encoded representation if the
295226584Sdim  /// specified value is a rotated 8-bit value. Return -1 if no rotation
296226584Sdim  /// encoding is possible.
297226584Sdim  /// See ARM Reference Manual A6.3.2.
298226584Sdim  static inline int getT2SOImmValRotateVal(unsigned V) {
299263509Sdim    unsigned RotAmt = countLeadingZeros(V);
300226584Sdim    if (RotAmt >= 24)
301226584Sdim      return -1;
302226584Sdim
303226584Sdim    // If 'Arg' can be handled with a single shifter_op return the value.
304226584Sdim    if ((rotr32(0xff000000U, RotAmt) & V) == V)
305226584Sdim      return (rotr32(V, 24 - RotAmt) & 0x7f) | ((RotAmt + 8) << 7);
306226584Sdim
307226584Sdim    return -1;
308226584Sdim  }
309226584Sdim
310226584Sdim  /// getT2SOImmVal - Given a 32-bit immediate, if it is something that can fit
311226584Sdim  /// into a Thumb-2 shifter_operand immediate operand, return the 12-bit
312226584Sdim  /// encoding for it.  If not, return -1.
313226584Sdim  /// See ARM Reference Manual A6.3.2.
314226584Sdim  static inline int getT2SOImmVal(unsigned Arg) {
315226584Sdim    // If 'Arg' is an 8-bit splat, then get the encoded value.
316226584Sdim    int Splat = getT2SOImmValSplatVal(Arg);
317226584Sdim    if (Splat != -1)
318226584Sdim      return Splat;
319226584Sdim
320226584Sdim    // If 'Arg' can be handled with a single shifter_op return the value.
321226584Sdim    int Rot = getT2SOImmValRotateVal(Arg);
322226584Sdim    if (Rot != -1)
323226584Sdim      return Rot;
324226584Sdim
325226584Sdim    return -1;
326226584Sdim  }
327226584Sdim
328226584Sdim  static inline unsigned getT2SOImmValRotate(unsigned V) {
329226584Sdim    if ((V & ~255U) == 0) return 0;
330226584Sdim    // Use CTZ to compute the rotate amount.
331263509Sdim    unsigned RotAmt = countTrailingZeros(V);
332226584Sdim    return (32 - RotAmt) & 31;
333226584Sdim  }
334226584Sdim
335226584Sdim  static inline bool isT2SOImmTwoPartVal (unsigned Imm) {
336226584Sdim    unsigned V = Imm;
337226584Sdim    // Passing values can be any combination of splat values and shifter
338226584Sdim    // values. If this can be handled with a single shifter or splat, bail
339226584Sdim    // out. Those should be handled directly, not with a two-part val.
340226584Sdim    if (getT2SOImmValSplatVal(V) != -1)
341226584Sdim      return false;
342226584Sdim    V = rotr32 (~255U, getT2SOImmValRotate(V)) & V;
343226584Sdim    if (V == 0)
344226584Sdim      return false;
345226584Sdim
346226584Sdim    // If this can be handled as an immediate, accept.
347226584Sdim    if (getT2SOImmVal(V) != -1) return true;
348226584Sdim
349226584Sdim    // Likewise, try masking out a splat value first.
350226584Sdim    V = Imm;
351226584Sdim    if (getT2SOImmValSplatVal(V & 0xff00ff00U) != -1)
352226584Sdim      V &= ~0xff00ff00U;
353226584Sdim    else if (getT2SOImmValSplatVal(V & 0x00ff00ffU) != -1)
354226584Sdim      V &= ~0x00ff00ffU;
355226584Sdim    // If what's left can be handled as an immediate, accept.
356226584Sdim    if (getT2SOImmVal(V) != -1) return true;
357226584Sdim
358226584Sdim    // Otherwise, do not accept.
359226584Sdim    return false;
360226584Sdim  }
361226584Sdim
362226584Sdim  static inline unsigned getT2SOImmTwoPartFirst(unsigned Imm) {
363226584Sdim    assert (isT2SOImmTwoPartVal(Imm) &&
364226584Sdim            "Immedate cannot be encoded as two part immediate!");
365226584Sdim    // Try a shifter operand as one part
366226584Sdim    unsigned V = rotr32 (~255, getT2SOImmValRotate(Imm)) & Imm;
367226584Sdim    // If the rest is encodable as an immediate, then return it.
368226584Sdim    if (getT2SOImmVal(V) != -1) return V;
369226584Sdim
370226584Sdim    // Try masking out a splat value first.
371226584Sdim    if (getT2SOImmValSplatVal(Imm & 0xff00ff00U) != -1)
372226584Sdim      return Imm & 0xff00ff00U;
373226584Sdim
374226584Sdim    // The other splat is all that's left as an option.
375226584Sdim    assert (getT2SOImmValSplatVal(Imm & 0x00ff00ffU) != -1);
376226584Sdim    return Imm & 0x00ff00ffU;
377226584Sdim  }
378226584Sdim
379226584Sdim  static inline unsigned getT2SOImmTwoPartSecond(unsigned Imm) {
380226584Sdim    // Mask out the first hunk
381226584Sdim    Imm ^= getT2SOImmTwoPartFirst(Imm);
382226584Sdim    // Return what's left
383226584Sdim    assert (getT2SOImmVal(Imm) != -1 &&
384226584Sdim            "Unable to encode second part of T2 two part SO immediate");
385226584Sdim    return Imm;
386226584Sdim  }
387226584Sdim
388226584Sdim
389226584Sdim  //===--------------------------------------------------------------------===//
390226584Sdim  // Addressing Mode #2
391226584Sdim  //===--------------------------------------------------------------------===//
392226584Sdim  //
393226584Sdim  // This is used for most simple load/store instructions.
394226584Sdim  //
395226584Sdim  // addrmode2 := reg +/- reg shop imm
396226584Sdim  // addrmode2 := reg +/- imm12
397226584Sdim  //
398226584Sdim  // The first operand is always a Reg.  The second operand is a reg if in
399226584Sdim  // reg/reg form, otherwise it's reg#0.  The third field encodes the operation
400226584Sdim  // in bit 12, the immediate in bits 0-11, and the shift op in 13-15. The
401226584Sdim  // fourth operand 16-17 encodes the index mode.
402226584Sdim  //
403226584Sdim  // If this addressing mode is a frame index (before prolog/epilog insertion
404226584Sdim  // and code rewriting), this operand will have the form:  FI#, reg0, <offs>
405226584Sdim  // with no shift amount for the frame offset.
406226584Sdim  //
407226584Sdim  static inline unsigned getAM2Opc(AddrOpc Opc, unsigned Imm12, ShiftOpc SO,
408226584Sdim                                   unsigned IdxMode = 0) {
409226584Sdim    assert(Imm12 < (1 << 12) && "Imm too large!");
410226584Sdim    bool isSub = Opc == sub;
411226584Sdim    return Imm12 | ((int)isSub << 12) | (SO << 13) | (IdxMode << 16) ;
412226584Sdim  }
413226584Sdim  static inline unsigned getAM2Offset(unsigned AM2Opc) {
414226584Sdim    return AM2Opc & ((1 << 12)-1);
415226584Sdim  }
416226584Sdim  static inline AddrOpc getAM2Op(unsigned AM2Opc) {
417226584Sdim    return ((AM2Opc >> 12) & 1) ? sub : add;
418226584Sdim  }
419226584Sdim  static inline ShiftOpc getAM2ShiftOpc(unsigned AM2Opc) {
420226584Sdim    return (ShiftOpc)((AM2Opc >> 13) & 7);
421226584Sdim  }
422226584Sdim  static inline unsigned getAM2IdxMode(unsigned AM2Opc) {
423226584Sdim    return (AM2Opc >> 16);
424226584Sdim  }
425226584Sdim
426226584Sdim
427226584Sdim  //===--------------------------------------------------------------------===//
428226584Sdim  // Addressing Mode #3
429226584Sdim  //===--------------------------------------------------------------------===//
430226584Sdim  //
431226584Sdim  // This is used for sign-extending loads, and load/store-pair instructions.
432226584Sdim  //
433226584Sdim  // addrmode3 := reg +/- reg
434226584Sdim  // addrmode3 := reg +/- imm8
435226584Sdim  //
436226584Sdim  // The first operand is always a Reg.  The second operand is a reg if in
437226584Sdim  // reg/reg form, otherwise it's reg#0.  The third field encodes the operation
438226584Sdim  // in bit 8, the immediate in bits 0-7. The fourth operand 9-10 encodes the
439226584Sdim  // index mode.
440226584Sdim
441226584Sdim  /// getAM3Opc - This function encodes the addrmode3 opc field.
442226584Sdim  static inline unsigned getAM3Opc(AddrOpc Opc, unsigned char Offset,
443226584Sdim                                   unsigned IdxMode = 0) {
444226584Sdim    bool isSub = Opc == sub;
445226584Sdim    return ((int)isSub << 8) | Offset | (IdxMode << 9);
446226584Sdim  }
447226584Sdim  static inline unsigned char getAM3Offset(unsigned AM3Opc) {
448226584Sdim    return AM3Opc & 0xFF;
449226584Sdim  }
450226584Sdim  static inline AddrOpc getAM3Op(unsigned AM3Opc) {
451226584Sdim    return ((AM3Opc >> 8) & 1) ? sub : add;
452226584Sdim  }
453226584Sdim  static inline unsigned getAM3IdxMode(unsigned AM3Opc) {
454226584Sdim    return (AM3Opc >> 9);
455226584Sdim  }
456226584Sdim
457226584Sdim  //===--------------------------------------------------------------------===//
458226584Sdim  // Addressing Mode #4
459226584Sdim  //===--------------------------------------------------------------------===//
460226584Sdim  //
461226584Sdim  // This is used for load / store multiple instructions.
462226584Sdim  //
463226584Sdim  // addrmode4 := reg, <mode>
464226584Sdim  //
465226584Sdim  // The four modes are:
466226584Sdim  //    IA - Increment after
467226584Sdim  //    IB - Increment before
468226584Sdim  //    DA - Decrement after
469226584Sdim  //    DB - Decrement before
470226584Sdim  // For VFP instructions, only the IA and DB modes are valid.
471226584Sdim
472226584Sdim  static inline AMSubMode getAM4SubMode(unsigned Mode) {
473226584Sdim    return (AMSubMode)(Mode & 0x7);
474226584Sdim  }
475226584Sdim
476226584Sdim  static inline unsigned getAM4ModeImm(AMSubMode SubMode) {
477226584Sdim    return (int)SubMode;
478226584Sdim  }
479226584Sdim
480226584Sdim  //===--------------------------------------------------------------------===//
481226584Sdim  // Addressing Mode #5
482226584Sdim  //===--------------------------------------------------------------------===//
483226584Sdim  //
484226584Sdim  // This is used for coprocessor instructions, such as FP load/stores.
485226584Sdim  //
486226584Sdim  // addrmode5 := reg +/- imm8*4
487226584Sdim  //
488226584Sdim  // The first operand is always a Reg.  The second operand encodes the
489226584Sdim  // operation in bit 8 and the immediate in bits 0-7.
490226584Sdim
491226584Sdim  /// getAM5Opc - This function encodes the addrmode5 opc field.
492226584Sdim  static inline unsigned getAM5Opc(AddrOpc Opc, unsigned char Offset) {
493226584Sdim    bool isSub = Opc == sub;
494226584Sdim    return ((int)isSub << 8) | Offset;
495226584Sdim  }
496226584Sdim  static inline unsigned char getAM5Offset(unsigned AM5Opc) {
497226584Sdim    return AM5Opc & 0xFF;
498226584Sdim  }
499226584Sdim  static inline AddrOpc getAM5Op(unsigned AM5Opc) {
500226584Sdim    return ((AM5Opc >> 8) & 1) ? sub : add;
501226584Sdim  }
502226584Sdim
503226584Sdim  //===--------------------------------------------------------------------===//
504226584Sdim  // Addressing Mode #6
505226584Sdim  //===--------------------------------------------------------------------===//
506226584Sdim  //
507226584Sdim  // This is used for NEON load / store instructions.
508226584Sdim  //
509226584Sdim  // addrmode6 := reg with optional alignment
510226584Sdim  //
511226584Sdim  // This is stored in two operands [regaddr, align].  The first is the
512226584Sdim  // address register.  The second operand is the value of the alignment
513226584Sdim  // specifier in bytes or zero if no explicit alignment.
514226584Sdim  // Valid alignments depend on the specific instruction.
515226584Sdim
516226584Sdim  //===--------------------------------------------------------------------===//
517226584Sdim  // NEON Modified Immediates
518226584Sdim  //===--------------------------------------------------------------------===//
519226584Sdim  //
520226584Sdim  // Several NEON instructions (e.g., VMOV) take a "modified immediate"
521226584Sdim  // vector operand, where a small immediate encoded in the instruction
522226584Sdim  // specifies a full NEON vector value.  These modified immediates are
523226584Sdim  // represented here as encoded integers.  The low 8 bits hold the immediate
524226584Sdim  // value; bit 12 holds the "Op" field of the instruction, and bits 11-8 hold
525226584Sdim  // the "Cmode" field of the instruction.  The interfaces below treat the
526226584Sdim  // Op and Cmode values as a single 5-bit value.
527226584Sdim
528226584Sdim  static inline unsigned createNEONModImm(unsigned OpCmode, unsigned Val) {
529226584Sdim    return (OpCmode << 8) | Val;
530226584Sdim  }
531226584Sdim  static inline unsigned getNEONModImmOpCmode(unsigned ModImm) {
532226584Sdim    return (ModImm >> 8) & 0x1f;
533226584Sdim  }
534226584Sdim  static inline unsigned getNEONModImmVal(unsigned ModImm) {
535226584Sdim    return ModImm & 0xff;
536226584Sdim  }
537226584Sdim
538226584Sdim  /// decodeNEONModImm - Decode a NEON modified immediate value into the
539226584Sdim  /// element value and the element size in bits.  (If the element size is
540226584Sdim  /// smaller than the vector, it is splatted into all the elements.)
541226584Sdim  static inline uint64_t decodeNEONModImm(unsigned ModImm, unsigned &EltBits) {
542226584Sdim    unsigned OpCmode = getNEONModImmOpCmode(ModImm);
543226584Sdim    unsigned Imm8 = getNEONModImmVal(ModImm);
544226584Sdim    uint64_t Val = 0;
545226584Sdim
546226584Sdim    if (OpCmode == 0xe) {
547226584Sdim      // 8-bit vector elements
548226584Sdim      Val = Imm8;
549226584Sdim      EltBits = 8;
550226584Sdim    } else if ((OpCmode & 0xc) == 0x8) {
551226584Sdim      // 16-bit vector elements
552226584Sdim      unsigned ByteNum = (OpCmode & 0x6) >> 1;
553226584Sdim      Val = Imm8 << (8 * ByteNum);
554226584Sdim      EltBits = 16;
555226584Sdim    } else if ((OpCmode & 0x8) == 0) {
556226584Sdim      // 32-bit vector elements, zero with one byte set
557226584Sdim      unsigned ByteNum = (OpCmode & 0x6) >> 1;
558226584Sdim      Val = Imm8 << (8 * ByteNum);
559226584Sdim      EltBits = 32;
560226584Sdim    } else if ((OpCmode & 0xe) == 0xc) {
561226584Sdim      // 32-bit vector elements, one byte with low bits set
562226584Sdim      unsigned ByteNum = 1 + (OpCmode & 0x1);
563226584Sdim      Val = (Imm8 << (8 * ByteNum)) | (0xffff >> (8 * (2 - ByteNum)));
564226584Sdim      EltBits = 32;
565226584Sdim    } else if (OpCmode == 0x1e) {
566226584Sdim      // 64-bit vector elements
567226584Sdim      for (unsigned ByteNum = 0; ByteNum < 8; ++ByteNum) {
568226584Sdim        if ((ModImm >> ByteNum) & 1)
569226584Sdim          Val |= (uint64_t)0xff << (8 * ByteNum);
570226584Sdim      }
571226584Sdim      EltBits = 64;
572226584Sdim    } else {
573235633Sdim      llvm_unreachable("Unsupported NEON immediate");
574226584Sdim    }
575226584Sdim    return Val;
576226584Sdim  }
577226584Sdim
578226584Sdim  AMSubMode getLoadStoreMultipleSubMode(int Opcode);
579226584Sdim
580226584Sdim  //===--------------------------------------------------------------------===//
581226584Sdim  // Floating-point Immediates
582226584Sdim  //
583226584Sdim  static inline float getFPImmFloat(unsigned Imm) {
584226584Sdim    // We expect an 8-bit binary encoding of a floating-point number here.
585226584Sdim    union {
586226584Sdim      uint32_t I;
587226584Sdim      float F;
588226584Sdim    } FPUnion;
589226584Sdim
590226584Sdim    uint8_t Sign = (Imm >> 7) & 0x1;
591226584Sdim    uint8_t Exp = (Imm >> 4) & 0x7;
592226584Sdim    uint8_t Mantissa = Imm & 0xf;
593226584Sdim
594226584Sdim    //   8-bit FP    iEEEE Float Encoding
595226584Sdim    //   abcd efgh   aBbbbbbc defgh000 00000000 00000000
596226584Sdim    //
597226584Sdim    // where B = NOT(b);
598226584Sdim
599226584Sdim    FPUnion.I = 0;
600226584Sdim    FPUnion.I |= Sign << 31;
601226584Sdim    FPUnion.I |= ((Exp & 0x4) != 0 ? 0 : 1) << 30;
602226584Sdim    FPUnion.I |= ((Exp & 0x4) != 0 ? 0x1f : 0) << 25;
603226584Sdim    FPUnion.I |= (Exp & 0x3) << 23;
604226584Sdim    FPUnion.I |= Mantissa << 19;
605226584Sdim    return FPUnion.F;
606226584Sdim  }
607226584Sdim
608226584Sdim  /// getFP32Imm - Return an 8-bit floating-point version of the 32-bit
609226584Sdim  /// floating-point value. If the value cannot be represented as an 8-bit
610226584Sdim  /// floating-point value, then return -1.
611226584Sdim  static inline int getFP32Imm(const APInt &Imm) {
612226584Sdim    uint32_t Sign = Imm.lshr(31).getZExtValue() & 1;
613226584Sdim    int32_t Exp = (Imm.lshr(23).getSExtValue() & 0xff) - 127;  // -126 to 127
614226584Sdim    int64_t Mantissa = Imm.getZExtValue() & 0x7fffff;  // 23 bits
615226584Sdim
616226584Sdim    // We can handle 4 bits of mantissa.
617226584Sdim    // mantissa = (16+UInt(e:f:g:h))/16.
618226584Sdim    if (Mantissa & 0x7ffff)
619226584Sdim      return -1;
620226584Sdim    Mantissa >>= 19;
621226584Sdim    if ((Mantissa & 0xf) != Mantissa)
622226584Sdim      return -1;
623226584Sdim
624226584Sdim    // We can handle 3 bits of exponent: exp == UInt(NOT(b):c:d)-3
625226584Sdim    if (Exp < -3 || Exp > 4)
626226584Sdim      return -1;
627226584Sdim    Exp = ((Exp+3) & 0x7) ^ 4;
628226584Sdim
629226584Sdim    return ((int)Sign << 7) | (Exp << 4) | Mantissa;
630226584Sdim  }
631226584Sdim
632226584Sdim  static inline int getFP32Imm(const APFloat &FPImm) {
633226584Sdim    return getFP32Imm(FPImm.bitcastToAPInt());
634226584Sdim  }
635226584Sdim
636226584Sdim  /// getFP64Imm - Return an 8-bit floating-point version of the 64-bit
637226584Sdim  /// floating-point value. If the value cannot be represented as an 8-bit
638226584Sdim  /// floating-point value, then return -1.
639226584Sdim  static inline int getFP64Imm(const APInt &Imm) {
640226584Sdim    uint64_t Sign = Imm.lshr(63).getZExtValue() & 1;
641226584Sdim    int64_t Exp = (Imm.lshr(52).getSExtValue() & 0x7ff) - 1023; // -1022 to 1023
642226584Sdim    uint64_t Mantissa = Imm.getZExtValue() & 0xfffffffffffffULL;
643226584Sdim
644226584Sdim    // We can handle 4 bits of mantissa.
645226584Sdim    // mantissa = (16+UInt(e:f:g:h))/16.
646226584Sdim    if (Mantissa & 0xffffffffffffULL)
647226584Sdim      return -1;
648226584Sdim    Mantissa >>= 48;
649226584Sdim    if ((Mantissa & 0xf) != Mantissa)
650226584Sdim      return -1;
651226584Sdim
652226584Sdim    // We can handle 3 bits of exponent: exp == UInt(NOT(b):c:d)-3
653226584Sdim    if (Exp < -3 || Exp > 4)
654226584Sdim      return -1;
655226584Sdim    Exp = ((Exp+3) & 0x7) ^ 4;
656226584Sdim
657226584Sdim    return ((int)Sign << 7) | (Exp << 4) | Mantissa;
658226584Sdim  }
659226584Sdim
660226584Sdim  static inline int getFP64Imm(const APFloat &FPImm) {
661226584Sdim    return getFP64Imm(FPImm.bitcastToAPInt());
662226584Sdim  }
663226584Sdim
664226584Sdim} // end namespace ARM_AM
665226584Sdim} // end namespace llvm
666226584Sdim
667226584Sdim#endif
668226584Sdim
669