#include <cassert>
namespace llvm {
-
+
/// ARM_AM - ARM Addressing Mode Stuff
namespace ARM_AM {
enum ShiftOpc {
ror,
rrx
};
-
+
enum AddrOpc {
add = '+', sub = '-'
};
-
+
static inline const char *getShiftOpcStr(ShiftOpc Op) {
switch (Op) {
default: assert(0 && "Unknown shift opc!");
case ARM_AM::rrx: return "rrx";
}
}
-
+
static inline ShiftOpc getShiftOpcForNode(SDValue N) {
switch (N.getOpcode()) {
default: return ARM_AM::no_shift;
assert(Amt < 32 && "Invalid rotate amount");
return (Val >> Amt) | (Val << ((32-Amt)&31));
}
-
+
/// rotl32 - Rotate a 32-bit unsigned value left by a specified # bits.
///
static inline unsigned rotl32(unsigned Val, unsigned Amt) {
assert(Amt < 32 && "Invalid rotate amount");
return (Val << Amt) | (Val >> ((32-Amt)&31));
}
-
+
//===--------------------------------------------------------------------===//
// Addressing Mode #1: shift_operand with registers
//===--------------------------------------------------------------------===//
static inline unsigned getSOImmValRot(unsigned Imm) {
return (Imm >> 8) * 2;
}
-
+
/// getSOImmValRotate - Try to handle Imm with an immediate shifter operand,
/// computing the rotate amount to use. If this immediate value cannot be
/// handled with a single shifter-op, determine a good rotate amount that will
// 8-bit (or less) immediates are trivially shifter_operands with a rotate
// of zero.
if ((Imm & ~255U) == 0) return 0;
-
+
// Use CTZ to compute the rotate amount.
unsigned TZ = CountTrailingZeros_32(Imm);
-
+
// Rotate amount must be even. Something like 0x200 must be rotated 8 bits,
// not 9.
unsigned RotAmt = TZ & ~1;
-
+
// If we can handle this spread, return it.
if ((rotr32(Imm, RotAmt) & ~255U) == 0)
return (32-RotAmt)&31; // HW rotates right, not left.
// Restart the search for a high-order bit after the initial seconds of
// ones.
unsigned TZ2 = CountTrailingZeros_32(Imm & ~((1 << TrailingOnes)-1));
-
+
// Rotate amount must be even.
unsigned RotAmt2 = TZ2 & ~1;
-
+
// If this fits, use it.
if (RotAmt2 != 32 && (rotr32(Imm, RotAmt2) & ~255U) == 0)
return (32-RotAmt2)&31; // HW rotates right, not left.
}
}
-
+
// Otherwise, we have no way to cover this span of bits with a single
// shifter_op immediate. Return a chunk of bits that will be useful to
// handle.
// 8-bit (or less) immediates are trivially shifter_operands with a rotate
// of zero.
if ((Arg & ~255U) == 0) return Arg;
-
+
unsigned RotAmt = getSOImmValRotate(Arg);
// If this cannot be handled with a single shifter_op, bail out.
if (rotr32(~255U, RotAmt) & Arg)
return -1;
-
+
// Encode this correctly.
return rotl32(Arg, RotAmt) | ((RotAmt>>1) << 8);
}
-
+
/// isSOImmTwoPartVal - Return true if the specified value can be obtained by
/// or'ing together two SOImmVal's.
static inline bool isSOImmTwoPartVal(unsigned V) {
V = rotr32(~255U, getSOImmValRotate(V)) & V;
if (V == 0)
return false;
-
+
// If this can be handled with two shifter_op's, accept.
V = rotr32(~255U, getSOImmValRotate(V)) & V;
return V == 0;
}
-
+
/// getSOImmTwoPartFirst - If V is a value that satisfies isSOImmTwoPartVal,
/// return the first chunk of it.
static inline unsigned getSOImmTwoPartFirst(unsigned V) {
/// getSOImmTwoPartSecond - If V is a value that satisfies isSOImmTwoPartVal,
/// return the second chunk of it.
static inline unsigned getSOImmTwoPartSecond(unsigned V) {
- // Mask out the first hunk.
+ // Mask out the first hunk.
V = rotr32(~255U, getSOImmValRotate(V)) & V;
-
+
// Take what's left.
assert(V == (rotr32(255U, getSOImmValRotate(V)) & V));
return V;
}
-
+
/// getThumbImmValShift - Try to handle Imm with a 8-bit immediate followed
/// by a left shift. Returns the shift amount to use.
static inline unsigned getThumbImmValShift(unsigned Imm) {
/// isThumbImmShiftedVal - Return true if the specified value can be obtained
/// by left shifting a 8-bit immediate.
static inline bool isThumbImmShiftedVal(unsigned V) {
- // If this can be handled with
+ // If this can be handled with
V = (~255U << getThumbImmValShift(V)) & V;
return V == 0;
}
return CountTrailingZeros_32(Imm);
}
- /// isThumbImm16ShiftedVal - Return true if the specified value can be
+ /// isThumbImm16ShiftedVal - Return true if the specified value can be
/// obtained by left shifting a 16-bit immediate.
static inline bool isThumbImm16ShiftedVal(unsigned V) {
- // If this can be handled with
+ // If this can be handled with
V = (~65535U << getThumbImm16ValShift(V)) & V;
return V == 0;
}
return V >> getThumbImmValShift(V);
}
- /// getT2SOImmValDecode - Given a 12-bit encoded Thumb-2 modified immediate,
- /// return the corresponding 32-bit immediate value.
- /// See ARM Reference Manual A6.3.2.
- static inline unsigned getT2SOImmValDecode(unsigned Imm) {
- unsigned Base = Imm & 0xff;
- switch ((Imm >> 8) & 0xf) {
- case 0:
- return Base;
- case 1:
- return Base | (Base << 16);
- case 2:
- return (Base << 8) | (Base << 24);
- case 3:
- return Base | (Base << 8) | (Base << 16) | (Base << 24);
- default:
- break;
- }
-
- // shifted immediate
- unsigned RotAmount = ((Imm >> 7) & 0x1f) - 8;
- return (Base | 0x80) << (24 - RotAmount);
- }
/// getT2SOImmValSplat - Return the 12-bit encoded representation
/// if the specified value can be obtained by splatting the low 8 bits
/// abcdefgh abcdefgh abcdefgh abcdefgh control = 3
/// Return -1 if none of the above apply.
/// See ARM Reference Manual A6.3.2.
- static inline int getT2SOImmValSplat(unsigned V) {
+ static inline int getT2SOImmValSplatVal(unsigned V) {
unsigned u, Vs, Imm;
// control = 0
- if ((V & 0xffffff00) == 0)
+ if ((V & 0xffffff00) == 0)
return V;
-
+
// If the value is zeroes in the first byte, just shift those off
Vs = ((V & 0xff) == 0) ? V >> 8 : V;
// Any passing value only has 8 bits of payload, splatted across the word
return -1;
}
- /// getT2SOImmValRotate - Return the 12-bit encoded representation if the
+ /// getT2SOImmValRotateVal - Return the 12-bit encoded representation if the
/// specified value is a rotated 8-bit value. Return -1 if no rotation
/// encoding is possible.
/// See ARM Reference Manual A6.3.2.
- static inline int getT2SOImmValRotate (unsigned V) {
+ static inline int getT2SOImmValRotateVal(unsigned V) {
unsigned RotAmt = CountLeadingZeros_32(V);
if (RotAmt >= 24)
return -1;
}
/// getT2SOImmVal - Given a 32-bit immediate, if it is something that can fit
- /// into a Thumb-2 shifter_operand immediate operand, return the 12-bit
+ /// into a Thumb-2 shifter_operand immediate operand, return the 12-bit
/// encoding for it. If not, return -1.
/// See ARM Reference Manual A6.3.2.
static inline int getT2SOImmVal(unsigned Arg) {
// If 'Arg' is an 8-bit splat, then get the encoded value.
- int Splat = getT2SOImmValSplat(Arg);
+ int Splat = getT2SOImmValSplatVal(Arg);
if (Splat != -1)
return Splat;
-
+
// If 'Arg' can be handled with a single shifter_op return the value.
- int Rot = getT2SOImmValRotate(Arg);
+ int Rot = getT2SOImmValRotateVal(Arg);
if (Rot != -1)
return Rot;
return -1;
}
-
+
+ static inline unsigned getT2SOImmValRotate(unsigned V) {
+ if ((V & ~255U) == 0) return 0;
+ // Use CTZ to compute the rotate amount.
+ unsigned RotAmt = CountTrailingZeros_32(V);
+ return (32 - RotAmt) & 31;
+ }
+
+ static inline bool isT2SOImmTwoPartVal (unsigned Imm) {
+ unsigned V = Imm;
+ // Passing values can be any combination of splat values and shifter
+ // values. If this can be handled with a single shifter or splat, bail
+ // out. Those should be handled directly, not with a two-part val.
+ if (getT2SOImmValSplatVal(V) != -1)
+ return false;
+ V = rotr32 (~255U, getT2SOImmValRotate(V)) & V;
+ if (V == 0)
+ return false;
+
+ // If this can be handled as an immediate, accept.
+ if (getT2SOImmVal(V) != -1) return true;
+
+ // Likewise, try masking out a splat value first.
+ V = Imm;
+ if (getT2SOImmValSplatVal(V & 0xff00ff00U) != -1)
+ V &= ~0xff00ff00U;
+ else if (getT2SOImmValSplatVal(V & 0x00ff00ffU) != -1)
+ V &= ~0x00ff00ffU;
+ // If what's left can be handled as an immediate, accept.
+ if (getT2SOImmVal(V) != -1) return true;
+
+ // Otherwise, do not accept.
+ return false;
+ }
+
+ static inline unsigned getT2SOImmTwoPartFirst(unsigned Imm) {
+ assert (isT2SOImmTwoPartVal(Imm) &&
+ "Immedate cannot be encoded as two part immediate!");
+ // Try a shifter operand as one part
+ unsigned V = rotr32 (~255, getT2SOImmValRotate(Imm)) & Imm;
+ // If the rest is encodable as an immediate, then return it.
+ if (getT2SOImmVal(V) != -1) return V;
+
+ // Try masking out a splat value first.
+ if (getT2SOImmValSplatVal(Imm & 0xff00ff00U) != -1)
+ return Imm & 0xff00ff00U;
+
+ // The other splat is all that's left as an option.
+ assert (getT2SOImmValSplatVal(Imm & 0x00ff00ffU) != -1);
+ return Imm & 0x00ff00ffU;
+ }
+
+ static inline unsigned getT2SOImmTwoPartSecond(unsigned Imm) {
+ // Mask out the first hunk
+ Imm ^= getT2SOImmTwoPartFirst(Imm);
+ // Return what's left
+ assert (getT2SOImmVal(Imm) != -1 &&
+ "Unable to encode second part of T2 two part SO immediate");
+ return Imm;
+ }
+
//===--------------------------------------------------------------------===//
// Addressing Mode #2
// If this addressing mode is a frame index (before prolog/epilog insertion
// and code rewriting), this operand will have the form: FI#, reg0, <offs>
// with no shift amount for the frame offset.
- //
+ //
static inline unsigned getAM2Opc(AddrOpc Opc, unsigned Imm12, ShiftOpc SO) {
assert(Imm12 < (1 << 12) && "Imm too large!");
bool isSub = Opc == sub;
static inline ShiftOpc getAM2ShiftOpc(unsigned AM2Opc) {
return (ShiftOpc)(AM2Opc >> 13);
}
-
-
+
+
//===--------------------------------------------------------------------===//
// Addressing Mode #3
//===--------------------------------------------------------------------===//
// The first operand is always a Reg. The second operand is a reg if in
// reg/reg form, otherwise it's reg#0. The third field encodes the operation
// in bit 8, the immediate in bits 0-7.
-
+
/// getAM3Opc - This function encodes the addrmode3 opc field.
static inline unsigned getAM3Opc(AddrOpc Opc, unsigned char Offset) {
bool isSub = Opc == sub;
static inline AddrOpc getAM3Op(unsigned AM3Opc) {
return ((AM3Opc >> 8) & 1) ? sub : add;
}
-
+
//===--------------------------------------------------------------------===//
// Addressing Mode #4
//===--------------------------------------------------------------------===//
//
// IA - Increment after
// DB - Decrement before
-
+
/// getAM5Opc - This function encodes the addrmode5 opc field.
static inline unsigned getAM5Opc(AddrOpc Opc, unsigned char Offset) {
bool isSub = Opc == sub;
static inline bool getAM5WBFlag(unsigned AM5Opc) {
return ((AM5Opc >> 8) & 1);
}
-
+
+ //===--------------------------------------------------------------------===//
+ // Addressing Mode #6
+ //===--------------------------------------------------------------------===//
+ //
+ // This is used for NEON load / store instructions.
+ //
+ // addrmode6 := reg with optional writeback
+ //
+ // This is stored in three operands [regaddr, regupdate, opc]. The first is
+ // the address register. The second register holds the value of a post-access
+ // increment for writeback or reg0 if no writeback or if the writeback
+ // increment is the size of the memory access. The third operand encodes
+ // whether there is writeback to the address register.
+
+ static inline unsigned getAM6Opc(bool WB = false) {
+ return (int)WB;
+ }
+
+ static inline bool getAM6WBFlag(unsigned Mode) {
+ return Mode & 1;
+ }
+
} // end namespace ARM_AM
} // end namespace llvm