106f32e7eSjoerg //===-- ARMAddressingModes.h - ARM Addressing Modes -------------*- C++ -*-===//
206f32e7eSjoerg //
306f32e7eSjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406f32e7eSjoerg // See https://llvm.org/LICENSE.txt for license information.
506f32e7eSjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606f32e7eSjoerg //
706f32e7eSjoerg //===----------------------------------------------------------------------===//
806f32e7eSjoerg //
906f32e7eSjoerg // This file contains the ARM addressing mode implementation stuff.
1006f32e7eSjoerg //
1106f32e7eSjoerg //===----------------------------------------------------------------------===//
1206f32e7eSjoerg 
1306f32e7eSjoerg #ifndef LLVM_LIB_TARGET_ARM_MCTARGETDESC_ARMADDRESSINGMODES_H
1406f32e7eSjoerg #define LLVM_LIB_TARGET_ARM_MCTARGETDESC_ARMADDRESSINGMODES_H
1506f32e7eSjoerg 
1606f32e7eSjoerg #include "llvm/ADT/APFloat.h"
1706f32e7eSjoerg #include "llvm/ADT/APInt.h"
1806f32e7eSjoerg #include "llvm/ADT/bit.h"
1906f32e7eSjoerg #include "llvm/Support/ErrorHandling.h"
2006f32e7eSjoerg #include "llvm/Support/MathExtras.h"
2106f32e7eSjoerg #include <cassert>
2206f32e7eSjoerg 
2306f32e7eSjoerg namespace llvm {
2406f32e7eSjoerg 
2506f32e7eSjoerg /// ARM_AM - ARM Addressing Mode Stuff
2606f32e7eSjoerg namespace ARM_AM {
2706f32e7eSjoerg   enum ShiftOpc {
2806f32e7eSjoerg     no_shift = 0,
2906f32e7eSjoerg     asr,
3006f32e7eSjoerg     lsl,
3106f32e7eSjoerg     lsr,
3206f32e7eSjoerg     ror,
3306f32e7eSjoerg     rrx,
3406f32e7eSjoerg     uxtw
3506f32e7eSjoerg   };
3606f32e7eSjoerg 
3706f32e7eSjoerg   enum AddrOpc {
3806f32e7eSjoerg     sub = 0,
3906f32e7eSjoerg     add
4006f32e7eSjoerg   };
4106f32e7eSjoerg 
getAddrOpcStr(AddrOpc Op)4206f32e7eSjoerg   inline const char *getAddrOpcStr(AddrOpc Op) { return Op == sub ? "-" : ""; }
4306f32e7eSjoerg 
getShiftOpcStr(ShiftOpc Op)4406f32e7eSjoerg   inline const char *getShiftOpcStr(ShiftOpc Op) {
4506f32e7eSjoerg     switch (Op) {
4606f32e7eSjoerg     default: llvm_unreachable("Unknown shift opc!");
4706f32e7eSjoerg     case ARM_AM::asr: return "asr";
4806f32e7eSjoerg     case ARM_AM::lsl: return "lsl";
4906f32e7eSjoerg     case ARM_AM::lsr: return "lsr";
5006f32e7eSjoerg     case ARM_AM::ror: return "ror";
5106f32e7eSjoerg     case ARM_AM::rrx: return "rrx";
5206f32e7eSjoerg     case ARM_AM::uxtw: return "uxtw";
5306f32e7eSjoerg     }
5406f32e7eSjoerg   }
5506f32e7eSjoerg 
getShiftOpcEncoding(ShiftOpc Op)5606f32e7eSjoerg   inline unsigned getShiftOpcEncoding(ShiftOpc Op) {
5706f32e7eSjoerg     switch (Op) {
5806f32e7eSjoerg     default: llvm_unreachable("Unknown shift opc!");
5906f32e7eSjoerg     case ARM_AM::asr: return 2;
6006f32e7eSjoerg     case ARM_AM::lsl: return 0;
6106f32e7eSjoerg     case ARM_AM::lsr: return 1;
6206f32e7eSjoerg     case ARM_AM::ror: return 3;
6306f32e7eSjoerg     }
6406f32e7eSjoerg   }
6506f32e7eSjoerg 
6606f32e7eSjoerg   enum AMSubMode {
6706f32e7eSjoerg     bad_am_submode = 0,
6806f32e7eSjoerg     ia,
6906f32e7eSjoerg     ib,
7006f32e7eSjoerg     da,
7106f32e7eSjoerg     db
7206f32e7eSjoerg   };
7306f32e7eSjoerg 
getAMSubModeStr(AMSubMode Mode)7406f32e7eSjoerg   inline const char *getAMSubModeStr(AMSubMode Mode) {
7506f32e7eSjoerg     switch (Mode) {
7606f32e7eSjoerg     default: llvm_unreachable("Unknown addressing sub-mode!");
7706f32e7eSjoerg     case ARM_AM::ia: return "ia";
7806f32e7eSjoerg     case ARM_AM::ib: return "ib";
7906f32e7eSjoerg     case ARM_AM::da: return "da";
8006f32e7eSjoerg     case ARM_AM::db: return "db";
8106f32e7eSjoerg     }
8206f32e7eSjoerg   }
8306f32e7eSjoerg 
8406f32e7eSjoerg   /// rotr32 - Rotate a 32-bit unsigned value right by a specified # bits.
8506f32e7eSjoerg   ///
rotr32(unsigned Val,unsigned Amt)8606f32e7eSjoerg   inline unsigned rotr32(unsigned Val, unsigned Amt) {
8706f32e7eSjoerg     assert(Amt < 32 && "Invalid rotate amount");
8806f32e7eSjoerg     return (Val >> Amt) | (Val << ((32-Amt)&31));
8906f32e7eSjoerg   }
9006f32e7eSjoerg 
9106f32e7eSjoerg   /// rotl32 - Rotate a 32-bit unsigned value left by a specified # bits.
9206f32e7eSjoerg   ///
rotl32(unsigned Val,unsigned Amt)9306f32e7eSjoerg   inline unsigned rotl32(unsigned Val, unsigned Amt) {
9406f32e7eSjoerg     assert(Amt < 32 && "Invalid rotate amount");
9506f32e7eSjoerg     return (Val << Amt) | (Val >> ((32-Amt)&31));
9606f32e7eSjoerg   }
9706f32e7eSjoerg 
9806f32e7eSjoerg   //===--------------------------------------------------------------------===//
9906f32e7eSjoerg   // Addressing Mode #1: shift_operand with registers
10006f32e7eSjoerg   //===--------------------------------------------------------------------===//
10106f32e7eSjoerg   //
10206f32e7eSjoerg   // This 'addressing mode' is used for arithmetic instructions.  It can
10306f32e7eSjoerg   // represent things like:
10406f32e7eSjoerg   //   reg
10506f32e7eSjoerg   //   reg [asr|lsl|lsr|ror|rrx] reg
10606f32e7eSjoerg   //   reg [asr|lsl|lsr|ror|rrx] imm
10706f32e7eSjoerg   //
10806f32e7eSjoerg   // This is stored three operands [rega, regb, opc].  The first is the base
10906f32e7eSjoerg   // reg, the second is the shift amount (or reg0 if not present or imm).  The
11006f32e7eSjoerg   // third operand encodes the shift opcode and the imm if a reg isn't present.
11106f32e7eSjoerg   //
getSORegOpc(ShiftOpc ShOp,unsigned Imm)11206f32e7eSjoerg   inline unsigned getSORegOpc(ShiftOpc ShOp, unsigned Imm) {
11306f32e7eSjoerg     return ShOp | (Imm << 3);
11406f32e7eSjoerg   }
getSORegOffset(unsigned Op)11506f32e7eSjoerg   inline unsigned getSORegOffset(unsigned Op) { return Op >> 3; }
getSORegShOp(unsigned Op)11606f32e7eSjoerg   inline ShiftOpc getSORegShOp(unsigned Op) { return (ShiftOpc)(Op & 7); }
11706f32e7eSjoerg 
11806f32e7eSjoerg   /// getSOImmValImm - Given an encoded imm field for the reg/imm form, return
11906f32e7eSjoerg   /// the 8-bit imm value.
getSOImmValImm(unsigned Imm)12006f32e7eSjoerg   inline unsigned getSOImmValImm(unsigned Imm) { return Imm & 0xFF; }
12106f32e7eSjoerg   /// getSOImmValRot - Given an encoded imm field for the reg/imm form, return
12206f32e7eSjoerg   /// the rotate amount.
getSOImmValRot(unsigned Imm)12306f32e7eSjoerg   inline unsigned getSOImmValRot(unsigned Imm) { return (Imm >> 8) * 2; }
12406f32e7eSjoerg 
12506f32e7eSjoerg   /// getSOImmValRotate - Try to handle Imm with an immediate shifter operand,
12606f32e7eSjoerg   /// computing the rotate amount to use.  If this immediate value cannot be
12706f32e7eSjoerg   /// handled with a single shifter-op, determine a good rotate amount that will
12806f32e7eSjoerg   /// take a maximal chunk of bits out of the immediate.
getSOImmValRotate(unsigned Imm)12906f32e7eSjoerg   inline unsigned getSOImmValRotate(unsigned Imm) {
13006f32e7eSjoerg     // 8-bit (or less) immediates are trivially shifter_operands with a rotate
13106f32e7eSjoerg     // of zero.
13206f32e7eSjoerg     if ((Imm & ~255U) == 0) return 0;
13306f32e7eSjoerg 
13406f32e7eSjoerg     // Use CTZ to compute the rotate amount.
13506f32e7eSjoerg     unsigned TZ = countTrailingZeros(Imm);
13606f32e7eSjoerg 
13706f32e7eSjoerg     // Rotate amount must be even.  Something like 0x200 must be rotated 8 bits,
13806f32e7eSjoerg     // not 9.
13906f32e7eSjoerg     unsigned RotAmt = TZ & ~1;
14006f32e7eSjoerg 
14106f32e7eSjoerg     // If we can handle this spread, return it.
14206f32e7eSjoerg     if ((rotr32(Imm, RotAmt) & ~255U) == 0)
14306f32e7eSjoerg       return (32-RotAmt)&31;  // HW rotates right, not left.
14406f32e7eSjoerg 
14506f32e7eSjoerg     // For values like 0xF000000F, we should ignore the low 6 bits, then
14606f32e7eSjoerg     // retry the hunt.
14706f32e7eSjoerg     if (Imm & 63U) {
14806f32e7eSjoerg       unsigned TZ2 = countTrailingZeros(Imm & ~63U);
14906f32e7eSjoerg       unsigned RotAmt2 = TZ2 & ~1;
15006f32e7eSjoerg       if ((rotr32(Imm, RotAmt2) & ~255U) == 0)
15106f32e7eSjoerg         return (32-RotAmt2)&31;  // HW rotates right, not left.
15206f32e7eSjoerg     }
15306f32e7eSjoerg 
15406f32e7eSjoerg     // Otherwise, we have no way to cover this span of bits with a single
15506f32e7eSjoerg     // shifter_op immediate.  Return a chunk of bits that will be useful to
15606f32e7eSjoerg     // handle.
15706f32e7eSjoerg     return (32-RotAmt)&31;  // HW rotates right, not left.
15806f32e7eSjoerg   }
15906f32e7eSjoerg 
16006f32e7eSjoerg   /// getSOImmVal - Given a 32-bit immediate, if it is something that can fit
16106f32e7eSjoerg   /// into an shifter_operand immediate operand, return the 12-bit encoding for
16206f32e7eSjoerg   /// it.  If not, return -1.
getSOImmVal(unsigned Arg)16306f32e7eSjoerg   inline int getSOImmVal(unsigned Arg) {
16406f32e7eSjoerg     // 8-bit (or less) immediates are trivially shifter_operands with a rotate
16506f32e7eSjoerg     // of zero.
16606f32e7eSjoerg     if ((Arg & ~255U) == 0) return Arg;
16706f32e7eSjoerg 
16806f32e7eSjoerg     unsigned RotAmt = getSOImmValRotate(Arg);
16906f32e7eSjoerg 
17006f32e7eSjoerg     // If this cannot be handled with a single shifter_op, bail out.
17106f32e7eSjoerg     if (rotr32(~255U, RotAmt) & Arg)
17206f32e7eSjoerg       return -1;
17306f32e7eSjoerg 
17406f32e7eSjoerg     // Encode this correctly.
17506f32e7eSjoerg     return rotl32(Arg, RotAmt) | ((RotAmt>>1) << 8);
17606f32e7eSjoerg   }
17706f32e7eSjoerg 
17806f32e7eSjoerg   /// isSOImmTwoPartVal - Return true if the specified value can be obtained by
17906f32e7eSjoerg   /// or'ing together two SOImmVal's.
isSOImmTwoPartVal(unsigned V)18006f32e7eSjoerg   inline bool isSOImmTwoPartVal(unsigned V) {
18106f32e7eSjoerg     // If this can be handled with a single shifter_op, bail out.
18206f32e7eSjoerg     V = rotr32(~255U, getSOImmValRotate(V)) & V;
18306f32e7eSjoerg     if (V == 0)
18406f32e7eSjoerg       return false;
18506f32e7eSjoerg 
18606f32e7eSjoerg     // If this can be handled with two shifter_op's, accept.
18706f32e7eSjoerg     V = rotr32(~255U, getSOImmValRotate(V)) & V;
18806f32e7eSjoerg     return V == 0;
18906f32e7eSjoerg   }
19006f32e7eSjoerg 
19106f32e7eSjoerg   /// getSOImmTwoPartFirst - If V is a value that satisfies isSOImmTwoPartVal,
19206f32e7eSjoerg   /// return the first chunk of it.
getSOImmTwoPartFirst(unsigned V)19306f32e7eSjoerg   inline unsigned getSOImmTwoPartFirst(unsigned V) {
19406f32e7eSjoerg     return rotr32(255U, getSOImmValRotate(V)) & V;
19506f32e7eSjoerg   }
19606f32e7eSjoerg 
19706f32e7eSjoerg   /// getSOImmTwoPartSecond - If V is a value that satisfies isSOImmTwoPartVal,
19806f32e7eSjoerg   /// return the second chunk of it.
getSOImmTwoPartSecond(unsigned V)19906f32e7eSjoerg   inline unsigned getSOImmTwoPartSecond(unsigned V) {
20006f32e7eSjoerg     // Mask out the first hunk.
20106f32e7eSjoerg     V = rotr32(~255U, getSOImmValRotate(V)) & V;
20206f32e7eSjoerg 
20306f32e7eSjoerg     // Take what's left.
20406f32e7eSjoerg     assert(V == (rotr32(255U, getSOImmValRotate(V)) & V));
20506f32e7eSjoerg     return V;
20606f32e7eSjoerg   }
20706f32e7eSjoerg 
208*da58b97aSjoerg   /// isSOImmTwoPartValNeg - Return true if the specified value can be obtained
209*da58b97aSjoerg   /// by two SOImmVal, that -V = First + Second.
210*da58b97aSjoerg   /// "R+V" can be optimized to (sub (sub R, First), Second).
211*da58b97aSjoerg   /// "R=V" can be optimized to (sub (mvn R, ~(-First)), Second).
isSOImmTwoPartValNeg(unsigned V)212*da58b97aSjoerg   inline bool isSOImmTwoPartValNeg(unsigned V) {
213*da58b97aSjoerg     unsigned First;
214*da58b97aSjoerg     if (!isSOImmTwoPartVal(-V))
215*da58b97aSjoerg       return false;
216*da58b97aSjoerg     // Return false if ~(-First) is not a SoImmval.
217*da58b97aSjoerg     First = getSOImmTwoPartFirst(-V);
218*da58b97aSjoerg     First = ~(-First);
219*da58b97aSjoerg     return !(rotr32(~255U, getSOImmValRotate(First)) & First);
220*da58b97aSjoerg   }
221*da58b97aSjoerg 
22206f32e7eSjoerg   /// getThumbImmValShift - Try to handle Imm with a 8-bit immediate followed
22306f32e7eSjoerg   /// by a left shift. Returns the shift amount to use.
getThumbImmValShift(unsigned Imm)22406f32e7eSjoerg   inline unsigned getThumbImmValShift(unsigned Imm) {
22506f32e7eSjoerg     // 8-bit (or less) immediates are trivially immediate operand with a shift
22606f32e7eSjoerg     // of zero.
22706f32e7eSjoerg     if ((Imm & ~255U) == 0) return 0;
22806f32e7eSjoerg 
22906f32e7eSjoerg     // Use CTZ to compute the shift amount.
23006f32e7eSjoerg     return countTrailingZeros(Imm);
23106f32e7eSjoerg   }
23206f32e7eSjoerg 
23306f32e7eSjoerg   /// isThumbImmShiftedVal - Return true if the specified value can be obtained
23406f32e7eSjoerg   /// by left shifting a 8-bit immediate.
isThumbImmShiftedVal(unsigned V)23506f32e7eSjoerg   inline bool isThumbImmShiftedVal(unsigned V) {
23606f32e7eSjoerg     // If this can be handled with
23706f32e7eSjoerg     V = (~255U << getThumbImmValShift(V)) & V;
23806f32e7eSjoerg     return V == 0;
23906f32e7eSjoerg   }
24006f32e7eSjoerg 
24106f32e7eSjoerg   /// getThumbImm16ValShift - Try to handle Imm with a 16-bit immediate followed
24206f32e7eSjoerg   /// by a left shift. Returns the shift amount to use.
getThumbImm16ValShift(unsigned Imm)24306f32e7eSjoerg   inline unsigned getThumbImm16ValShift(unsigned Imm) {
24406f32e7eSjoerg     // 16-bit (or less) immediates are trivially immediate operand with a shift
24506f32e7eSjoerg     // of zero.
24606f32e7eSjoerg     if ((Imm & ~65535U) == 0) return 0;
24706f32e7eSjoerg 
24806f32e7eSjoerg     // Use CTZ to compute the shift amount.
24906f32e7eSjoerg     return countTrailingZeros(Imm);
25006f32e7eSjoerg   }
25106f32e7eSjoerg 
25206f32e7eSjoerg   /// isThumbImm16ShiftedVal - Return true if the specified value can be
25306f32e7eSjoerg   /// obtained by left shifting a 16-bit immediate.
isThumbImm16ShiftedVal(unsigned V)25406f32e7eSjoerg   inline bool isThumbImm16ShiftedVal(unsigned V) {
25506f32e7eSjoerg     // If this can be handled with
25606f32e7eSjoerg     V = (~65535U << getThumbImm16ValShift(V)) & V;
25706f32e7eSjoerg     return V == 0;
25806f32e7eSjoerg   }
25906f32e7eSjoerg 
26006f32e7eSjoerg   /// getThumbImmNonShiftedVal - If V is a value that satisfies
26106f32e7eSjoerg   /// isThumbImmShiftedVal, return the non-shiftd value.
getThumbImmNonShiftedVal(unsigned V)26206f32e7eSjoerg   inline unsigned getThumbImmNonShiftedVal(unsigned V) {
26306f32e7eSjoerg     return V >> getThumbImmValShift(V);
26406f32e7eSjoerg   }
26506f32e7eSjoerg 
26606f32e7eSjoerg 
26706f32e7eSjoerg   /// getT2SOImmValSplat - Return the 12-bit encoded representation
26806f32e7eSjoerg   /// if the specified value can be obtained by splatting the low 8 bits
26906f32e7eSjoerg   /// into every other byte or every byte of a 32-bit value. i.e.,
27006f32e7eSjoerg   ///     00000000 00000000 00000000 abcdefgh    control = 0
27106f32e7eSjoerg   ///     00000000 abcdefgh 00000000 abcdefgh    control = 1
27206f32e7eSjoerg   ///     abcdefgh 00000000 abcdefgh 00000000    control = 2
27306f32e7eSjoerg   ///     abcdefgh abcdefgh abcdefgh abcdefgh    control = 3
27406f32e7eSjoerg   /// Return -1 if none of the above apply.
27506f32e7eSjoerg   /// See ARM Reference Manual A6.3.2.
getT2SOImmValSplatVal(unsigned V)27606f32e7eSjoerg   inline int getT2SOImmValSplatVal(unsigned V) {
27706f32e7eSjoerg     unsigned u, Vs, Imm;
27806f32e7eSjoerg     // control = 0
27906f32e7eSjoerg     if ((V & 0xffffff00) == 0)
28006f32e7eSjoerg       return V;
28106f32e7eSjoerg 
28206f32e7eSjoerg     // If the value is zeroes in the first byte, just shift those off
28306f32e7eSjoerg     Vs = ((V & 0xff) == 0) ? V >> 8 : V;
28406f32e7eSjoerg     // Any passing value only has 8 bits of payload, splatted across the word
28506f32e7eSjoerg     Imm = Vs & 0xff;
28606f32e7eSjoerg     // Likewise, any passing values have the payload splatted into the 3rd byte
28706f32e7eSjoerg     u = Imm | (Imm << 16);
28806f32e7eSjoerg 
28906f32e7eSjoerg     // control = 1 or 2
29006f32e7eSjoerg     if (Vs == u)
29106f32e7eSjoerg       return (((Vs == V) ? 1 : 2) << 8) | Imm;
29206f32e7eSjoerg 
29306f32e7eSjoerg     // control = 3
29406f32e7eSjoerg     if (Vs == (u | (u << 8)))
29506f32e7eSjoerg       return (3 << 8) | Imm;
29606f32e7eSjoerg 
29706f32e7eSjoerg     return -1;
29806f32e7eSjoerg   }
29906f32e7eSjoerg 
30006f32e7eSjoerg   /// getT2SOImmValRotateVal - Return the 12-bit encoded representation if the
30106f32e7eSjoerg   /// specified value is a rotated 8-bit value. Return -1 if no rotation
30206f32e7eSjoerg   /// encoding is possible.
30306f32e7eSjoerg   /// See ARM Reference Manual A6.3.2.
getT2SOImmValRotateVal(unsigned V)30406f32e7eSjoerg   inline int getT2SOImmValRotateVal(unsigned V) {
30506f32e7eSjoerg     unsigned RotAmt = countLeadingZeros(V);
30606f32e7eSjoerg     if (RotAmt >= 24)
30706f32e7eSjoerg       return -1;
30806f32e7eSjoerg 
30906f32e7eSjoerg     // If 'Arg' can be handled with a single shifter_op return the value.
31006f32e7eSjoerg     if ((rotr32(0xff000000U, RotAmt) & V) == V)
31106f32e7eSjoerg       return (rotr32(V, 24 - RotAmt) & 0x7f) | ((RotAmt + 8) << 7);
31206f32e7eSjoerg 
31306f32e7eSjoerg     return -1;
31406f32e7eSjoerg   }
31506f32e7eSjoerg 
31606f32e7eSjoerg   /// getT2SOImmVal - Given a 32-bit immediate, if it is something that can fit
31706f32e7eSjoerg   /// into a Thumb-2 shifter_operand immediate operand, return the 12-bit
31806f32e7eSjoerg   /// encoding for it.  If not, return -1.
31906f32e7eSjoerg   /// See ARM Reference Manual A6.3.2.
getT2SOImmVal(unsigned Arg)32006f32e7eSjoerg   inline int getT2SOImmVal(unsigned Arg) {
32106f32e7eSjoerg     // If 'Arg' is an 8-bit splat, then get the encoded value.
32206f32e7eSjoerg     int Splat = getT2SOImmValSplatVal(Arg);
32306f32e7eSjoerg     if (Splat != -1)
32406f32e7eSjoerg       return Splat;
32506f32e7eSjoerg 
32606f32e7eSjoerg     // If 'Arg' can be handled with a single shifter_op return the value.
32706f32e7eSjoerg     int Rot = getT2SOImmValRotateVal(Arg);
32806f32e7eSjoerg     if (Rot != -1)
32906f32e7eSjoerg       return Rot;
33006f32e7eSjoerg 
33106f32e7eSjoerg     return -1;
33206f32e7eSjoerg   }
33306f32e7eSjoerg 
getT2SOImmValRotate(unsigned V)33406f32e7eSjoerg   inline unsigned getT2SOImmValRotate(unsigned V) {
33506f32e7eSjoerg     if ((V & ~255U) == 0) return 0;
33606f32e7eSjoerg     // Use CTZ to compute the rotate amount.
33706f32e7eSjoerg     unsigned RotAmt = countTrailingZeros(V);
33806f32e7eSjoerg     return (32 - RotAmt) & 31;
33906f32e7eSjoerg   }
34006f32e7eSjoerg 
isT2SOImmTwoPartVal(unsigned Imm)34106f32e7eSjoerg   inline bool isT2SOImmTwoPartVal(unsigned Imm) {
34206f32e7eSjoerg     unsigned V = Imm;
34306f32e7eSjoerg     // Passing values can be any combination of splat values and shifter
34406f32e7eSjoerg     // values. If this can be handled with a single shifter or splat, bail
34506f32e7eSjoerg     // out. Those should be handled directly, not with a two-part val.
34606f32e7eSjoerg     if (getT2SOImmValSplatVal(V) != -1)
34706f32e7eSjoerg       return false;
34806f32e7eSjoerg     V = rotr32 (~255U, getT2SOImmValRotate(V)) & V;
34906f32e7eSjoerg     if (V == 0)
35006f32e7eSjoerg       return false;
35106f32e7eSjoerg 
35206f32e7eSjoerg     // If this can be handled as an immediate, accept.
35306f32e7eSjoerg     if (getT2SOImmVal(V) != -1) return true;
35406f32e7eSjoerg 
35506f32e7eSjoerg     // Likewise, try masking out a splat value first.
35606f32e7eSjoerg     V = Imm;
35706f32e7eSjoerg     if (getT2SOImmValSplatVal(V & 0xff00ff00U) != -1)
35806f32e7eSjoerg       V &= ~0xff00ff00U;
35906f32e7eSjoerg     else if (getT2SOImmValSplatVal(V & 0x00ff00ffU) != -1)
36006f32e7eSjoerg       V &= ~0x00ff00ffU;
36106f32e7eSjoerg     // If what's left can be handled as an immediate, accept.
36206f32e7eSjoerg     if (getT2SOImmVal(V) != -1) return true;
36306f32e7eSjoerg 
36406f32e7eSjoerg     // Otherwise, do not accept.
36506f32e7eSjoerg     return false;
36606f32e7eSjoerg   }
36706f32e7eSjoerg 
getT2SOImmTwoPartFirst(unsigned Imm)36806f32e7eSjoerg   inline unsigned getT2SOImmTwoPartFirst(unsigned Imm) {
36906f32e7eSjoerg     assert (isT2SOImmTwoPartVal(Imm) &&
37006f32e7eSjoerg             "Immedate cannot be encoded as two part immediate!");
37106f32e7eSjoerg     // Try a shifter operand as one part
37206f32e7eSjoerg     unsigned V = rotr32 (~255, getT2SOImmValRotate(Imm)) & Imm;
37306f32e7eSjoerg     // If the rest is encodable as an immediate, then return it.
37406f32e7eSjoerg     if (getT2SOImmVal(V) != -1) return V;
37506f32e7eSjoerg 
37606f32e7eSjoerg     // Try masking out a splat value first.
37706f32e7eSjoerg     if (getT2SOImmValSplatVal(Imm & 0xff00ff00U) != -1)
37806f32e7eSjoerg       return Imm & 0xff00ff00U;
37906f32e7eSjoerg 
38006f32e7eSjoerg     // The other splat is all that's left as an option.
38106f32e7eSjoerg     assert (getT2SOImmValSplatVal(Imm & 0x00ff00ffU) != -1);
38206f32e7eSjoerg     return Imm & 0x00ff00ffU;
38306f32e7eSjoerg   }
38406f32e7eSjoerg 
getT2SOImmTwoPartSecond(unsigned Imm)38506f32e7eSjoerg   inline unsigned getT2SOImmTwoPartSecond(unsigned Imm) {
38606f32e7eSjoerg     // Mask out the first hunk
38706f32e7eSjoerg     Imm ^= getT2SOImmTwoPartFirst(Imm);
38806f32e7eSjoerg     // Return what's left
38906f32e7eSjoerg     assert (getT2SOImmVal(Imm) != -1 &&
39006f32e7eSjoerg             "Unable to encode second part of T2 two part SO immediate");
39106f32e7eSjoerg     return Imm;
39206f32e7eSjoerg   }
39306f32e7eSjoerg 
39406f32e7eSjoerg 
39506f32e7eSjoerg   //===--------------------------------------------------------------------===//
39606f32e7eSjoerg   // Addressing Mode #2
39706f32e7eSjoerg   //===--------------------------------------------------------------------===//
39806f32e7eSjoerg   //
39906f32e7eSjoerg   // This is used for most simple load/store instructions.
40006f32e7eSjoerg   //
40106f32e7eSjoerg   // addrmode2 := reg +/- reg shop imm
40206f32e7eSjoerg   // addrmode2 := reg +/- imm12
40306f32e7eSjoerg   //
40406f32e7eSjoerg   // The first operand is always a Reg.  The second operand is a reg if in
40506f32e7eSjoerg   // reg/reg form, otherwise it's reg#0.  The third field encodes the operation
40606f32e7eSjoerg   // in bit 12, the immediate in bits 0-11, and the shift op in 13-15. The
40706f32e7eSjoerg   // fourth operand 16-17 encodes the index mode.
40806f32e7eSjoerg   //
40906f32e7eSjoerg   // If this addressing mode is a frame index (before prolog/epilog insertion
41006f32e7eSjoerg   // and code rewriting), this operand will have the form:  FI#, reg0, <offs>
41106f32e7eSjoerg   // with no shift amount for the frame offset.
41206f32e7eSjoerg   //
41306f32e7eSjoerg   inline unsigned getAM2Opc(AddrOpc Opc, unsigned Imm12, ShiftOpc SO,
41406f32e7eSjoerg                             unsigned IdxMode = 0) {
41506f32e7eSjoerg     assert(Imm12 < (1 << 12) && "Imm too large!");
41606f32e7eSjoerg     bool isSub = Opc == sub;
41706f32e7eSjoerg     return Imm12 | ((int)isSub << 12) | (SO << 13) | (IdxMode << 16) ;
41806f32e7eSjoerg   }
getAM2Offset(unsigned AM2Opc)41906f32e7eSjoerg   inline unsigned getAM2Offset(unsigned AM2Opc) {
42006f32e7eSjoerg     return AM2Opc & ((1 << 12)-1);
42106f32e7eSjoerg   }
getAM2Op(unsigned AM2Opc)42206f32e7eSjoerg   inline AddrOpc getAM2Op(unsigned AM2Opc) {
42306f32e7eSjoerg     return ((AM2Opc >> 12) & 1) ? sub : add;
42406f32e7eSjoerg   }
getAM2ShiftOpc(unsigned AM2Opc)42506f32e7eSjoerg   inline ShiftOpc getAM2ShiftOpc(unsigned AM2Opc) {
42606f32e7eSjoerg     return (ShiftOpc)((AM2Opc >> 13) & 7);
42706f32e7eSjoerg   }
getAM2IdxMode(unsigned AM2Opc)42806f32e7eSjoerg   inline unsigned getAM2IdxMode(unsigned AM2Opc) { return (AM2Opc >> 16); }
42906f32e7eSjoerg 
43006f32e7eSjoerg   //===--------------------------------------------------------------------===//
43106f32e7eSjoerg   // Addressing Mode #3
43206f32e7eSjoerg   //===--------------------------------------------------------------------===//
43306f32e7eSjoerg   //
43406f32e7eSjoerg   // This is used for sign-extending loads, and load/store-pair instructions.
43506f32e7eSjoerg   //
43606f32e7eSjoerg   // addrmode3 := reg +/- reg
43706f32e7eSjoerg   // addrmode3 := reg +/- imm8
43806f32e7eSjoerg   //
43906f32e7eSjoerg   // The first operand is always a Reg.  The second operand is a reg if in
44006f32e7eSjoerg   // reg/reg form, otherwise it's reg#0.  The third field encodes the operation
44106f32e7eSjoerg   // in bit 8, the immediate in bits 0-7. The fourth operand 9-10 encodes the
44206f32e7eSjoerg   // index mode.
44306f32e7eSjoerg 
44406f32e7eSjoerg   /// getAM3Opc - This function encodes the addrmode3 opc field.
44506f32e7eSjoerg   inline unsigned getAM3Opc(AddrOpc Opc, unsigned char Offset,
44606f32e7eSjoerg                             unsigned IdxMode = 0) {
44706f32e7eSjoerg     bool isSub = Opc == sub;
44806f32e7eSjoerg     return ((int)isSub << 8) | Offset | (IdxMode << 9);
44906f32e7eSjoerg   }
getAM3Offset(unsigned AM3Opc)45006f32e7eSjoerg   inline unsigned char getAM3Offset(unsigned AM3Opc) { return AM3Opc & 0xFF; }
getAM3Op(unsigned AM3Opc)45106f32e7eSjoerg   inline AddrOpc getAM3Op(unsigned AM3Opc) {
45206f32e7eSjoerg     return ((AM3Opc >> 8) & 1) ? sub : add;
45306f32e7eSjoerg   }
getAM3IdxMode(unsigned AM3Opc)45406f32e7eSjoerg   inline unsigned getAM3IdxMode(unsigned AM3Opc) { return (AM3Opc >> 9); }
45506f32e7eSjoerg 
45606f32e7eSjoerg   //===--------------------------------------------------------------------===//
45706f32e7eSjoerg   // Addressing Mode #4
45806f32e7eSjoerg   //===--------------------------------------------------------------------===//
45906f32e7eSjoerg   //
46006f32e7eSjoerg   // This is used for load / store multiple instructions.
46106f32e7eSjoerg   //
46206f32e7eSjoerg   // addrmode4 := reg, <mode>
46306f32e7eSjoerg   //
46406f32e7eSjoerg   // The four modes are:
46506f32e7eSjoerg   //    IA - Increment after
46606f32e7eSjoerg   //    IB - Increment before
46706f32e7eSjoerg   //    DA - Decrement after
46806f32e7eSjoerg   //    DB - Decrement before
46906f32e7eSjoerg   // For VFP instructions, only the IA and DB modes are valid.
47006f32e7eSjoerg 
getAM4SubMode(unsigned Mode)47106f32e7eSjoerg   inline AMSubMode getAM4SubMode(unsigned Mode) {
47206f32e7eSjoerg     return (AMSubMode)(Mode & 0x7);
47306f32e7eSjoerg   }
47406f32e7eSjoerg 
getAM4ModeImm(AMSubMode SubMode)47506f32e7eSjoerg   inline unsigned getAM4ModeImm(AMSubMode SubMode) { return (int)SubMode; }
47606f32e7eSjoerg 
47706f32e7eSjoerg   //===--------------------------------------------------------------------===//
47806f32e7eSjoerg   // Addressing Mode #5
47906f32e7eSjoerg   //===--------------------------------------------------------------------===//
48006f32e7eSjoerg   //
48106f32e7eSjoerg   // This is used for coprocessor instructions, such as FP load/stores.
48206f32e7eSjoerg   //
48306f32e7eSjoerg   // addrmode5 := reg +/- imm8*4
48406f32e7eSjoerg   //
48506f32e7eSjoerg   // The first operand is always a Reg.  The second operand encodes the
48606f32e7eSjoerg   // operation (add or subtract) in bit 8 and the immediate in bits 0-7.
48706f32e7eSjoerg 
48806f32e7eSjoerg   /// getAM5Opc - This function encodes the addrmode5 opc field.
getAM5Opc(AddrOpc Opc,unsigned char Offset)48906f32e7eSjoerg   inline unsigned getAM5Opc(AddrOpc Opc, unsigned char Offset) {
49006f32e7eSjoerg     bool isSub = Opc == sub;
49106f32e7eSjoerg     return ((int)isSub << 8) | Offset;
49206f32e7eSjoerg   }
getAM5Offset(unsigned AM5Opc)49306f32e7eSjoerg   inline unsigned char getAM5Offset(unsigned AM5Opc) { return AM5Opc & 0xFF; }
getAM5Op(unsigned AM5Opc)49406f32e7eSjoerg   inline AddrOpc getAM5Op(unsigned AM5Opc) {
49506f32e7eSjoerg     return ((AM5Opc >> 8) & 1) ? sub : add;
49606f32e7eSjoerg   }
49706f32e7eSjoerg 
49806f32e7eSjoerg   //===--------------------------------------------------------------------===//
49906f32e7eSjoerg   // Addressing Mode #5 FP16
50006f32e7eSjoerg   //===--------------------------------------------------------------------===//
50106f32e7eSjoerg   //
50206f32e7eSjoerg   // This is used for coprocessor instructions, such as 16-bit FP load/stores.
50306f32e7eSjoerg   //
50406f32e7eSjoerg   // addrmode5fp16 := reg +/- imm8*2
50506f32e7eSjoerg   //
50606f32e7eSjoerg   // The first operand is always a Reg.  The second operand encodes the
50706f32e7eSjoerg   // operation (add or subtract) in bit 8 and the immediate in bits 0-7.
50806f32e7eSjoerg 
50906f32e7eSjoerg   /// getAM5FP16Opc - This function encodes the addrmode5fp16 opc field.
getAM5FP16Opc(AddrOpc Opc,unsigned char Offset)51006f32e7eSjoerg   inline unsigned getAM5FP16Opc(AddrOpc Opc, unsigned char Offset) {
51106f32e7eSjoerg     bool isSub = Opc == sub;
51206f32e7eSjoerg     return ((int)isSub << 8) | Offset;
51306f32e7eSjoerg   }
getAM5FP16Offset(unsigned AM5Opc)51406f32e7eSjoerg   inline unsigned char getAM5FP16Offset(unsigned AM5Opc) {
51506f32e7eSjoerg     return AM5Opc & 0xFF;
51606f32e7eSjoerg   }
getAM5FP16Op(unsigned AM5Opc)51706f32e7eSjoerg   inline AddrOpc getAM5FP16Op(unsigned AM5Opc) {
51806f32e7eSjoerg     return ((AM5Opc >> 8) & 1) ? sub : add;
51906f32e7eSjoerg   }
52006f32e7eSjoerg 
52106f32e7eSjoerg   //===--------------------------------------------------------------------===//
52206f32e7eSjoerg   // Addressing Mode #6
52306f32e7eSjoerg   //===--------------------------------------------------------------------===//
52406f32e7eSjoerg   //
52506f32e7eSjoerg   // This is used for NEON load / store instructions.
52606f32e7eSjoerg   //
52706f32e7eSjoerg   // addrmode6 := reg with optional alignment
52806f32e7eSjoerg   //
52906f32e7eSjoerg   // This is stored in two operands [regaddr, align].  The first is the
53006f32e7eSjoerg   // address register.  The second operand is the value of the alignment
53106f32e7eSjoerg   // specifier in bytes or zero if no explicit alignment.
53206f32e7eSjoerg   // Valid alignments depend on the specific instruction.
53306f32e7eSjoerg 
53406f32e7eSjoerg   //===--------------------------------------------------------------------===//
53506f32e7eSjoerg   // NEON/MVE Modified Immediates
53606f32e7eSjoerg   //===--------------------------------------------------------------------===//
53706f32e7eSjoerg   //
53806f32e7eSjoerg   // Several NEON and MVE instructions (e.g., VMOV) take a "modified immediate"
53906f32e7eSjoerg   // vector operand, where a small immediate encoded in the instruction
54006f32e7eSjoerg   // specifies a full NEON vector value.  These modified immediates are
54106f32e7eSjoerg   // represented here as encoded integers.  The low 8 bits hold the immediate
54206f32e7eSjoerg   // value; bit 12 holds the "Op" field of the instruction, and bits 11-8 hold
54306f32e7eSjoerg   // the "Cmode" field of the instruction.  The interfaces below treat the
54406f32e7eSjoerg   // Op and Cmode values as a single 5-bit value.
54506f32e7eSjoerg 
createVMOVModImm(unsigned OpCmode,unsigned Val)54606f32e7eSjoerg   inline unsigned createVMOVModImm(unsigned OpCmode, unsigned Val) {
54706f32e7eSjoerg     return (OpCmode << 8) | Val;
54806f32e7eSjoerg   }
getVMOVModImmOpCmode(unsigned ModImm)54906f32e7eSjoerg   inline unsigned getVMOVModImmOpCmode(unsigned ModImm) {
55006f32e7eSjoerg     return (ModImm >> 8) & 0x1f;
55106f32e7eSjoerg   }
getVMOVModImmVal(unsigned ModImm)55206f32e7eSjoerg   inline unsigned getVMOVModImmVal(unsigned ModImm) { return ModImm & 0xff; }
55306f32e7eSjoerg 
55406f32e7eSjoerg   /// decodeVMOVModImm - Decode a NEON/MVE modified immediate value into the
55506f32e7eSjoerg   /// element value and the element size in bits.  (If the element size is
55606f32e7eSjoerg   /// smaller than the vector, it is splatted into all the elements.)
decodeVMOVModImm(unsigned ModImm,unsigned & EltBits)55706f32e7eSjoerg   inline uint64_t decodeVMOVModImm(unsigned ModImm, unsigned &EltBits) {
55806f32e7eSjoerg     unsigned OpCmode = getVMOVModImmOpCmode(ModImm);
55906f32e7eSjoerg     unsigned Imm8 = getVMOVModImmVal(ModImm);
56006f32e7eSjoerg     uint64_t Val = 0;
56106f32e7eSjoerg 
56206f32e7eSjoerg     if (OpCmode == 0xe) {
56306f32e7eSjoerg       // 8-bit vector elements
56406f32e7eSjoerg       Val = Imm8;
56506f32e7eSjoerg       EltBits = 8;
56606f32e7eSjoerg     } else if ((OpCmode & 0xc) == 0x8) {
56706f32e7eSjoerg       // 16-bit vector elements
56806f32e7eSjoerg       unsigned ByteNum = (OpCmode & 0x6) >> 1;
56906f32e7eSjoerg       Val = Imm8 << (8 * ByteNum);
57006f32e7eSjoerg       EltBits = 16;
57106f32e7eSjoerg     } else if ((OpCmode & 0x8) == 0) {
57206f32e7eSjoerg       // 32-bit vector elements, zero with one byte set
57306f32e7eSjoerg       unsigned ByteNum = (OpCmode & 0x6) >> 1;
57406f32e7eSjoerg       Val = Imm8 << (8 * ByteNum);
57506f32e7eSjoerg       EltBits = 32;
57606f32e7eSjoerg     } else if ((OpCmode & 0xe) == 0xc) {
57706f32e7eSjoerg       // 32-bit vector elements, one byte with low bits set
57806f32e7eSjoerg       unsigned ByteNum = 1 + (OpCmode & 0x1);
57906f32e7eSjoerg       Val = (Imm8 << (8 * ByteNum)) | (0xffff >> (8 * (2 - ByteNum)));
58006f32e7eSjoerg       EltBits = 32;
58106f32e7eSjoerg     } else if (OpCmode == 0x1e) {
58206f32e7eSjoerg       // 64-bit vector elements
58306f32e7eSjoerg       for (unsigned ByteNum = 0; ByteNum < 8; ++ByteNum) {
58406f32e7eSjoerg         if ((ModImm >> ByteNum) & 1)
58506f32e7eSjoerg           Val |= (uint64_t)0xff << (8 * ByteNum);
58606f32e7eSjoerg       }
58706f32e7eSjoerg       EltBits = 64;
58806f32e7eSjoerg     } else {
58906f32e7eSjoerg       llvm_unreachable("Unsupported VMOV immediate");
59006f32e7eSjoerg     }
59106f32e7eSjoerg     return Val;
59206f32e7eSjoerg   }
59306f32e7eSjoerg 
59406f32e7eSjoerg   // Generic validation for single-byte immediate (0X00, 00X0, etc).
isNEONBytesplat(unsigned Value,unsigned Size)59506f32e7eSjoerg   inline bool isNEONBytesplat(unsigned Value, unsigned Size) {
59606f32e7eSjoerg     assert(Size >= 1 && Size <= 4 && "Invalid size");
59706f32e7eSjoerg     unsigned count = 0;
59806f32e7eSjoerg     for (unsigned i = 0; i < Size; ++i) {
59906f32e7eSjoerg       if (Value & 0xff) count++;
60006f32e7eSjoerg       Value >>= 8;
60106f32e7eSjoerg     }
60206f32e7eSjoerg     return count == 1;
60306f32e7eSjoerg   }
60406f32e7eSjoerg 
60506f32e7eSjoerg   /// Checks if Value is a correct immediate for instructions like VBIC/VORR.
isNEONi16splat(unsigned Value)60606f32e7eSjoerg   inline bool isNEONi16splat(unsigned Value) {
60706f32e7eSjoerg     if (Value > 0xffff)
60806f32e7eSjoerg       return false;
60906f32e7eSjoerg     // i16 value with set bits only in one byte X0 or 0X.
61006f32e7eSjoerg     return Value == 0 || isNEONBytesplat(Value, 2);
61106f32e7eSjoerg   }
61206f32e7eSjoerg 
61306f32e7eSjoerg   // Encode NEON 16 bits Splat immediate for instructions like VBIC/VORR
encodeNEONi16splat(unsigned Value)61406f32e7eSjoerg   inline unsigned encodeNEONi16splat(unsigned Value) {
61506f32e7eSjoerg     assert(isNEONi16splat(Value) && "Invalid NEON splat value");
61606f32e7eSjoerg     if (Value >= 0x100)
61706f32e7eSjoerg       Value = (Value >> 8) | 0xa00;
61806f32e7eSjoerg     else
61906f32e7eSjoerg       Value |= 0x800;
62006f32e7eSjoerg     return Value;
62106f32e7eSjoerg   }
62206f32e7eSjoerg 
62306f32e7eSjoerg   /// Checks if Value is a correct immediate for instructions like VBIC/VORR.
isNEONi32splat(unsigned Value)62406f32e7eSjoerg   inline bool isNEONi32splat(unsigned Value) {
62506f32e7eSjoerg     // i32 value with set bits only in one byte X000, 0X00, 00X0, or 000X.
62606f32e7eSjoerg     return Value == 0 || isNEONBytesplat(Value, 4);
62706f32e7eSjoerg   }
62806f32e7eSjoerg 
62906f32e7eSjoerg   /// Encode NEON 32 bits Splat immediate for instructions like VBIC/VORR.
encodeNEONi32splat(unsigned Value)63006f32e7eSjoerg   inline unsigned encodeNEONi32splat(unsigned Value) {
63106f32e7eSjoerg     assert(isNEONi32splat(Value) && "Invalid NEON splat value");
63206f32e7eSjoerg     if (Value >= 0x100 && Value <= 0xff00)
63306f32e7eSjoerg       Value = (Value >> 8) | 0x200;
63406f32e7eSjoerg     else if (Value > 0xffff && Value <= 0xff0000)
63506f32e7eSjoerg       Value = (Value >> 16) | 0x400;
63606f32e7eSjoerg     else if (Value > 0xffffff)
63706f32e7eSjoerg       Value = (Value >> 24) | 0x600;
63806f32e7eSjoerg     return Value;
63906f32e7eSjoerg   }
64006f32e7eSjoerg 
64106f32e7eSjoerg   //===--------------------------------------------------------------------===//
64206f32e7eSjoerg   // Floating-point Immediates
64306f32e7eSjoerg   //
getFPImmFloat(unsigned Imm)64406f32e7eSjoerg   inline float getFPImmFloat(unsigned Imm) {
64506f32e7eSjoerg     // We expect an 8-bit binary encoding of a floating-point number here.
64606f32e7eSjoerg 
64706f32e7eSjoerg     uint8_t Sign = (Imm >> 7) & 0x1;
64806f32e7eSjoerg     uint8_t Exp = (Imm >> 4) & 0x7;
64906f32e7eSjoerg     uint8_t Mantissa = Imm & 0xf;
65006f32e7eSjoerg 
65106f32e7eSjoerg     //   8-bit FP    IEEE Float Encoding
65206f32e7eSjoerg     //   abcd efgh   aBbbbbbc defgh000 00000000 00000000
65306f32e7eSjoerg     //
65406f32e7eSjoerg     // where B = NOT(b);
65506f32e7eSjoerg     uint32_t I = 0;
65606f32e7eSjoerg     I |= Sign << 31;
65706f32e7eSjoerg     I |= ((Exp & 0x4) != 0 ? 0 : 1) << 30;
65806f32e7eSjoerg     I |= ((Exp & 0x4) != 0 ? 0x1f : 0) << 25;
65906f32e7eSjoerg     I |= (Exp & 0x3) << 23;
66006f32e7eSjoerg     I |= Mantissa << 19;
66106f32e7eSjoerg     return bit_cast<float>(I);
66206f32e7eSjoerg   }
66306f32e7eSjoerg 
66406f32e7eSjoerg   /// getFP16Imm - Return an 8-bit floating-point version of the 16-bit
66506f32e7eSjoerg   /// floating-point value. If the value cannot be represented as an 8-bit
66606f32e7eSjoerg   /// floating-point value, then return -1.
getFP16Imm(const APInt & Imm)66706f32e7eSjoerg   inline int getFP16Imm(const APInt &Imm) {
66806f32e7eSjoerg     uint32_t Sign = Imm.lshr(15).getZExtValue() & 1;
66906f32e7eSjoerg     int32_t Exp = (Imm.lshr(10).getSExtValue() & 0x1f) - 15;  // -14 to 15
67006f32e7eSjoerg     int64_t Mantissa = Imm.getZExtValue() & 0x3ff;  // 10 bits
67106f32e7eSjoerg 
67206f32e7eSjoerg     // We can handle 4 bits of mantissa.
67306f32e7eSjoerg     // mantissa = (16+UInt(e:f:g:h))/16.
67406f32e7eSjoerg     if (Mantissa & 0x3f)
67506f32e7eSjoerg       return -1;
67606f32e7eSjoerg     Mantissa >>= 6;
67706f32e7eSjoerg 
67806f32e7eSjoerg     // We can handle 3 bits of exponent: exp == UInt(NOT(b):c:d)-3
67906f32e7eSjoerg     if (Exp < -3 || Exp > 4)
68006f32e7eSjoerg       return -1;
68106f32e7eSjoerg     Exp = ((Exp+3) & 0x7) ^ 4;
68206f32e7eSjoerg 
68306f32e7eSjoerg     return ((int)Sign << 7) | (Exp << 4) | Mantissa;
68406f32e7eSjoerg   }
68506f32e7eSjoerg 
getFP16Imm(const APFloat & FPImm)68606f32e7eSjoerg   inline int getFP16Imm(const APFloat &FPImm) {
68706f32e7eSjoerg     return getFP16Imm(FPImm.bitcastToAPInt());
68806f32e7eSjoerg   }
68906f32e7eSjoerg 
690*da58b97aSjoerg   /// If this is a FP16Imm encoded as a fp32 value, return the 8-bit encoding
691*da58b97aSjoerg   /// for it. Otherwise return -1 like getFP16Imm.
getFP32FP16Imm(const APInt & Imm)692*da58b97aSjoerg   inline int getFP32FP16Imm(const APInt &Imm) {
693*da58b97aSjoerg     if (Imm.getActiveBits() > 16)
694*da58b97aSjoerg       return -1;
695*da58b97aSjoerg     return ARM_AM::getFP16Imm(Imm.trunc(16));
696*da58b97aSjoerg   }
697*da58b97aSjoerg 
getFP32FP16Imm(const APFloat & FPImm)698*da58b97aSjoerg   inline int getFP32FP16Imm(const APFloat &FPImm) {
699*da58b97aSjoerg     return getFP32FP16Imm(FPImm.bitcastToAPInt());
700*da58b97aSjoerg   }
701*da58b97aSjoerg 
70206f32e7eSjoerg   /// getFP32Imm - Return an 8-bit floating-point version of the 32-bit
70306f32e7eSjoerg   /// floating-point value. If the value cannot be represented as an 8-bit
70406f32e7eSjoerg   /// floating-point value, then return -1.
getFP32Imm(const APInt & Imm)70506f32e7eSjoerg   inline int getFP32Imm(const APInt &Imm) {
70606f32e7eSjoerg     uint32_t Sign = Imm.lshr(31).getZExtValue() & 1;
70706f32e7eSjoerg     int32_t Exp = (Imm.lshr(23).getSExtValue() & 0xff) - 127;  // -126 to 127
70806f32e7eSjoerg     int64_t Mantissa = Imm.getZExtValue() & 0x7fffff;  // 23 bits
70906f32e7eSjoerg 
71006f32e7eSjoerg     // We can handle 4 bits of mantissa.
71106f32e7eSjoerg     // mantissa = (16+UInt(e:f:g:h))/16.
71206f32e7eSjoerg     if (Mantissa & 0x7ffff)
71306f32e7eSjoerg       return -1;
71406f32e7eSjoerg     Mantissa >>= 19;
71506f32e7eSjoerg     if ((Mantissa & 0xf) != Mantissa)
71606f32e7eSjoerg       return -1;
71706f32e7eSjoerg 
71806f32e7eSjoerg     // We can handle 3 bits of exponent: exp == UInt(NOT(b):c:d)-3
71906f32e7eSjoerg     if (Exp < -3 || Exp > 4)
72006f32e7eSjoerg       return -1;
72106f32e7eSjoerg     Exp = ((Exp+3) & 0x7) ^ 4;
72206f32e7eSjoerg 
72306f32e7eSjoerg     return ((int)Sign << 7) | (Exp << 4) | Mantissa;
72406f32e7eSjoerg   }
72506f32e7eSjoerg 
getFP32Imm(const APFloat & FPImm)72606f32e7eSjoerg   inline int getFP32Imm(const APFloat &FPImm) {
72706f32e7eSjoerg     return getFP32Imm(FPImm.bitcastToAPInt());
72806f32e7eSjoerg   }
72906f32e7eSjoerg 
73006f32e7eSjoerg   /// getFP64Imm - Return an 8-bit floating-point version of the 64-bit
73106f32e7eSjoerg   /// floating-point value. If the value cannot be represented as an 8-bit
73206f32e7eSjoerg   /// floating-point value, then return -1.
getFP64Imm(const APInt & Imm)73306f32e7eSjoerg   inline int getFP64Imm(const APInt &Imm) {
73406f32e7eSjoerg     uint64_t Sign = Imm.lshr(63).getZExtValue() & 1;
73506f32e7eSjoerg     int64_t Exp = (Imm.lshr(52).getSExtValue() & 0x7ff) - 1023; // -1022 to 1023
73606f32e7eSjoerg     uint64_t Mantissa = Imm.getZExtValue() & 0xfffffffffffffULL;
73706f32e7eSjoerg 
73806f32e7eSjoerg     // We can handle 4 bits of mantissa.
73906f32e7eSjoerg     // mantissa = (16+UInt(e:f:g:h))/16.
74006f32e7eSjoerg     if (Mantissa & 0xffffffffffffULL)
74106f32e7eSjoerg       return -1;
74206f32e7eSjoerg     Mantissa >>= 48;
74306f32e7eSjoerg     if ((Mantissa & 0xf) != Mantissa)
74406f32e7eSjoerg       return -1;
74506f32e7eSjoerg 
74606f32e7eSjoerg     // We can handle 3 bits of exponent: exp == UInt(NOT(b):c:d)-3
74706f32e7eSjoerg     if (Exp < -3 || Exp > 4)
74806f32e7eSjoerg       return -1;
74906f32e7eSjoerg     Exp = ((Exp+3) & 0x7) ^ 4;
75006f32e7eSjoerg 
75106f32e7eSjoerg     return ((int)Sign << 7) | (Exp << 4) | Mantissa;
75206f32e7eSjoerg   }
75306f32e7eSjoerg 
getFP64Imm(const APFloat & FPImm)75406f32e7eSjoerg   inline int getFP64Imm(const APFloat &FPImm) {
75506f32e7eSjoerg     return getFP64Imm(FPImm.bitcastToAPInt());
75606f32e7eSjoerg   }
75706f32e7eSjoerg 
75806f32e7eSjoerg } // end namespace ARM_AM
75906f32e7eSjoerg } // end namespace llvm
76006f32e7eSjoerg 
76106f32e7eSjoerg #endif
76206f32e7eSjoerg 
763