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